题目传送门: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
",ans);
return 0;
}