逆序对的两种求法(复习)

逆序对

对于一个数列\(a_1...a_n\),定义一有序对\((i,j)\)当且仅当\(i<j\)且\(a_i>a_j\)为逆序对。接着我们来考虑怎么求

*1. 归并排序

回顾归并排序的过程,将当且的数列\([l,r]\)分成两个长度相等的部分\([l,mid]\)和\([mid+1,r]\),分治下去排序,每次合并的代价是区间的长度,所以得到时间复杂度为:
\[
T(n)=2T(\frac{n}{2})+O(n)
\]
根据\(master\)定理可知时间复杂度为\(\Theta(nlog_2n)\)

int MergeSort (int l, int r) {
    if (l == r) return ;
    int mid = (l + r) >> 1;
    MergeSort(l, mid), MergeSort(mid + 1, r);
    int i = l, j = mid + 1, t = l;
    while(i <= mid && j <= r)
        if (a[i] <= a[j]) b[t++] = a[i++];
        else b[t++] = a[j++];
    while(i <= mid) b[t++] = a[i++]; while(j <= r) b[t++] = a[j++];
    for(int k = l; k <= r; ++k) a[k] = b[k];
}

等一下!你讲了这么久,到底怎么求逆序对???



我们截取一段代码:

else b[t++] = a[j++]

由于归并排序是将一个区间分成左右两端,故右边一段中的任何一个元素一定在左边一段中任何一个元素之后,这种性质同样用于分治处理,所以,当我们加入一个右区间元素时,此时左区间中剩下没加入的元素一定就比它大,所以改写一下:

else b[t++] = a[j++], ans += mid - i + 1;//ans为逆序对个数

由于分治的性质,所以每个逆序对都会不重不漏地选到。

*2. 树状数组

\(BIT\)作为一种巧妙的数据结构,其利用了一种类似于前缀和的思想。通过权值\(BIT\)来求解逆序对。

其算法核心在于,先确立\(a_j<a_i\)的大小关系,按从小到大插入其下标,通过计算前缀和的方式来求解。

比如我们现在有一个数\(a_i\),我们向\(BIT\)中插入其下标\(i\)后计算当前小于等于其下标的数的个数\(tot\),则答案就是\(i-tot\)。

因为此时\(a_i>a_j\)(\(j\)为之前已插入的数的下标),所以\(i-tot\)即位置在\(i\)之后的个数就是当前\(i\) 对答案产生的贡献(满足\(a_j<a_i\&j>i\))。

#include <cstdio>
#include <algorithm>
typedef long long ll;
using std::sort;

const ll N = 5e5 + 10;
ll n, a[N], b[N], c[N], ans;

inline bool cmp (ll x, ll y) { return a[x] < a[y] || (a[x] == a[y] && x < y); }
inline ll lowbit (ll x) { return x & (-x); }
inline void add (ll x, ll y) { for (; x <= n; x += lowbit(x)) c[x] += y; }
inline ll query (ll x) { ll y = 0; for (; x > 0; x -= lowbit(x)) y += c[x]; return y; }

int main () {
    scanf ("%lld", &n);
    for (ll i = 1; i <= n; ++i) scanf ("%lld", a + i), b[i] = i;
    sort (b + 1, b + n + 1, cmp);
    for (ll i = 1; i <= n; ++i) add(b[i], 1). ans += i - query (b[i]);
    printf ("%lld\n", ans);
    return 0;
} 

原文地址:https://www.cnblogs.com/water-mi/p/9811731.html

时间: 2024-10-04 04:21:16

逆序对的两种求法(复习)的相关文章

统计逆序对的两种解法

统计逆序对的两种解法 归并排序(mergeSort) 逆序对定义 \(i<j\) 但\(a[i]>a[j]\),假设我们分别使得通过mergeSort使得左右半边有序 即\(a[1]...a[mid]\) 递增, \(a[mid+1]....a[n]\)递增,我们需要通过merge操作,完成整个的排序和新增逆序对的计数,较小值出现在左半边记为 a[i],出现在右半边即为 a[j],那么每次出现在右半边,意味左半边比a[i]大的数都比a[j]大,由此可以统计逆序对 HDU1394 代码实现 #i

逆序对的三种解法

设 A 为一个有 n 个数字的有序集 (n>1),其中所有数字各不相同. 如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 而且 A[i] > A[j],则 <A[i], A[j]> 这个有序对称为 A 的一个逆序对. 逆序对的解法 第一种:冒泡法(暴力)/ 枚举 直接对原序列进行冒泡排序,统计交换次数,得到的交换次数=逆序对数. 注:求相邻元素的交换次数等价于求序列的逆序对数 第二种:归并排序 对原序列进行归并排序,在每次合并两数组时可以直接统计逆序对的个数.针对

逆序数的几种求法

逆序数的几种求法 白话经典算法系列之九 从归并排序到数列的逆序数对(微软笔试题)

LCA的两种求法

HDU 2586 题意:一棵树,多次询问任意两点的路径长度. LCA:最近公共祖先Least Common Ancestors.两个节点向根爬,第一个碰在一起的结点. 求出x, y的最近公共祖先lca后,假设dist[x]为x到根的距离,那么x->y的距离为dist[x]+dist[y]-2*dist[lca] 求最近公共祖先解法常见的有两种 1, tarjan+并查集 2,树上倍增 首先是树上倍增. 1 #include <cstdio> 2 #include <cstring&

JS中如何在外部引用私有变量的两种方法 复习

引用:https://blog.csdn.net/liwenfei123/article/details/77964222 运用闭包的特权方法 在构造函数中定义特权方法 这种模式在构造函数中定义了所有私有变量和函数. 能够在构造函数中定义特权方法是因为特权方法作为闭包,能够访问在构造函数中定义的所有变量和函数. function product(){ var name='yuxiaoliang'; this.getName=function(){ return name; } } var obj

双向链表的逆置(两种)

#include<iostream> #include<string> using namespace std; template<class T> struct LinkNode { LinkNode(const T& x) :_data(x) , _prev(NULL) , _next(NULL) { } T _data; LinkNode<T>* _prev; LinkNode<T>* _next; }; template<c

Inversion (hdu 4911 树状数组 || 归并排序 求逆序对)

Inversion Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 2003    Accepted Submission(s): 787 Problem Description bobo has a sequence a1,a2,-,an. He is allowed to swap two adjacent numbers fo

【CQOI2011】动态逆序对 BZOJ3295

Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. Output 输出包含m行,依次为删除每个元素之前,逆序对的个数. Sample Input 5 4 1 5 3

HDU 1394 Minimum Inversion Number(逆序对问题)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 16585 Accepted Submission(s): 10093 Problem Description The inversion number of a given number sequence a1, a2, -, an is th