逆序数(数列上的分治法)

题解一:使用树状数组在O(nlogn)的时间内解决了这个问题,

题解二:使用数列上的分治法进行统计,可以将数列A分为两半得到数列B和数列C。于是,数列A中所有的逆序对必然是下面三者之一

1.i,j都属于数列B的逆序对(i,j)

2.i,j都属于数列C的逆序对(i,j)

3.i属于数列B而j属于数列C的逆序对(i,j)

所以,只要分别统计这三种逆序对,再把结果相加到一起就行了,对于1和2通过递归求得,对于3,我们可以统计数列C中的每个数字,统计时在数列B中比它大的数字的个数,再把结果相加起来就好了,这就可以通过在归并排序的同时进行统计得到。

每次递归长度都会减半,所以递归的深度为O(logn),而每一层总的操作都是O(n),所以总的复杂度为O(nlogn).

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

vector<int>A;

ll merge_count(vector<int>&a)
{
    int n=a.size();
    if(n<=1){
        return 0;
    }
    ll cnt=0;
    vector<int>b(a.begin(),a.begin()+n/2);
    vector<int>c(a.begin()+n/2,a.end());
    cnt+=merge_count(b);
    cnt+=merge_count(c);
    int ai=0,bi=0,ci=0;
    while(ai<n){
        if(bi<b.size()&&(ci==c.size()||b[bi]<=c[ci])){
            a[ai++]=b[bi++];
        }else{
            cnt+=n/2-bi;
            a[ai++]=c[ci++];
        }
    }
    return cnt;
}

void solve()
{
    printf("%lld\n",merge_count(A));
}

int main()
{
    //输入A
    solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhouzi2018/article/details/82796117