题目:luogu1908.
题目大意:给定一串序列,求逆序对对数,其中逆序对定义为i<j且a[i]>a[j]的数对.
这道题很水,分治思想的简单应用.
首先我们可以想到归并排序(这里默认为从小到大排序),这个时候我们的归并排序需要一个返回值,表示在这个数列中的逆序对数量.
那么两段数列如何合并成一段数列呢?我们直接先把当前的答案先加上两段数列的答案和,然后在合并过程中,当前面一段数列[l,mid+1]中有数进来时,说明这个数只比它早进入数列的数大,也就是说它只能跟比它前面进入的数成逆序对,而跟它同样在前半段数列[l,mid+1]的数已经被统计过,所以只考虑后半段有多少数进入了,那么就是剩下的还要增加的数列.
然后合并的时候其实有一个细节,就是当a[i]=a[j]的时候,其中i是在前半部分的指针,j是在后半部分的指针,我们应该先加入a[i],原因是因为逆序对的定义是a[i]>a[j]而不是a[i]>=a[j].
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=40000;
int a[N+1],r[N+1],n;
int mergesort(int L,int R){
if (L==R) return 0;
int mid=L+R>>1,sum=mergesort(L,mid)+mergesort(mid+1,R),i=L,j=mid+1,k=L;
while (i<=mid&&j<=R)
if (a[i]<=a[j]) sum+=j-mid-1,r[k++]=a[i++];
else r[k++]=a[j++];
while (i<=mid) sum+=j-mid-1,r[k++]=a[i++];
while (j<=R) r[k++]=a[j++];
for (int t=L;t<=R;t++) a[t]=r[t];
return sum;
}
Abigail into(){
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
}
Abigail work(){
}
Abigail outo(){
printf("%d\n",mergesort(1,n));
}
int main(){
into();
work();
outo();
return 0;
}