洛谷【P1908】逆序对

题目传送门:https://www.luogu.org/problemnew/show/P1908

所谓逆序对,就是序列中\(a[i]>a[j]\)\(i<j\)的有序对。

所以我们在归并排序的时候可以顺便把这个玩意儿的个数求了。

如果你不知道归并排序是啥,那么就去看看这个:

https://www.cnblogs.com/AKMer/p/9645807.html

如果\(a[pos1]>a[pos2]\),那么\([pos1,mid]\)都将比\(a[pos2]\)大,就会产生\(mid-pos1+1\)对逆序对。

区间内部的逆序对我们在递归的时候已经统计完了,所以我们只需要会统计第一个数在\([l,mid]\),第二个数在\([mid+1,r]\)中的逆序对就可以了。

时间复杂度:\(O(nlogn)\)

空间复杂度:\(O(n)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
#define ll long long

const int maxn=5e5+5;

int n;
ll ans;
int a[maxn],p[maxn];

int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}

void merge_sort(int l,int r) {
    if(l==r)return;
    int mid=(l+r)>>1;
    merge_sort(l,mid);
    merge_sort(mid+1,r);
    int pos1=l,pos2=mid+1,pos=l;
    while(pos1<=mid&&pos2<=r) {
        if(a[pos1]<=a[pos2])p[pos++]=a[pos1++];
        else p[pos++]=a[pos2++],ans+=mid-pos1+1;//统计答案
    }
    while(pos1<=mid)p[pos++]=a[pos1++];
    while(pos2<=r)p[pos++]=a[pos2++];
    for(int i=l;i<=r;i++)a[i]=p[i];
}

int main() {
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    merge_sort(1,n);
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/AKMer/p/9646541.html