AcWing 788.逆序对的数量

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;
}
原文地址:https://www.cnblogs.com/Lngstart/p/14261024.html