AcWing 788.逆序对的数量
原题链接
思路
- 暴力的思路
暴力是最容易想到的思路,但是时间复杂度有点高,当数组中数比较多的时候一般会超时
代码如下:
ll res = 0;
for(int i = 0; i < n; ++ i){
for(int j = i + 1; j < n; ++ j){
if(q[i] > q[j]) res ++;
}
}
- 归并排序的方式
这个题目是归并排序的一个拓展应用,逆序对是下标小而数值大的一对数,我们知道在归并排序的过程中,每次分为两组进行比较,前面一组的下标比后面一组下标要小,如果在比较的过程中发现了逆序对,因为每一组中都是有序的,那么其后面的数都可以与后面分组中的那个数构成逆序对,这样就可以快速的求出逆序对的数量。
这样做时间复杂度降为了O(NlogN)
代码如下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
int n, tmp[N];
ll mager_sort(int q[], int l, int r){
if(l >= r) return 0;
int mid = l + r >> 1;
//总的逆序对的数量等于左边分组、右边分组和左右两边之和(其中左边和右边由递归返回求出)
ll res = mager_sort(q, l, mid) + mager_sort(q, mid + 1, r);
int i = l, j = mid + 1, k = 0;
while(i <= mid && j <= r){
if(q[i] <= q[j]) tmp[k ++] = q[i ++];
else {
res += mid - i + 1;//如果此时q[i] > q[j]那么i所在的分组中后续所有的数都比q[j]大
tmp[k ++] = q[j ++];
}
}
while(i <= mid) tmp[k ++] = q[i ++];
while(j <= r) tmp[k ++] = q[j ++];
for(i = l, j = 0; i <= r; ++ i, ++ j) q[i] = tmp[j];
return res;
}
int main(){
ios::sync_with_stdio(false);
int q[N]; cin >> n;
for(int i = 0; i < n; ++ i) cin >> q[i];
cout << mager_sort(q, 0, n - 1) << endl;
return 0;
}