洛谷【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
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/AKMer/p/9646541.html