【题目描述】
现给定1,2,…,n的一个排列,求它的逆序数。
【输入格式】
第一行是一个整数n,表示该排列有n个数(n <= 100000)。
第二行是n个不同的正整数,之间以空格隔开,表示该排列。
【输出格式】
输出该排列的逆序数。
【分析】
(1)将区间[1..n]进行二分,先求出区间[1,mid]和[mid+1,n],而子区间又进行二分直到区间内只有一个元素。
(2)将已经排好序的子区间进行合并,即用有序的[L,K][K+1,R]求出有序的区间[L,R]最终合并成区间[1,N],而合并区间分为若干步:
①令i=j,j=mid+1,变量k=L,执行下一步。
②如果i<=mid,且j<=r,若a[i]<a[j],则令c[sum]=a[i],i++,sum++;
若a[i]>=a[j],则令c[sum]=a[j],j++,sum++,执行下一步,如果i>k,或j>r,则把令一个区间的剩下元素都放到c数组中,执行下一步。
③如果sum>r,则跳出循环。
求逆序对:在合并区间的第二步中在a[i]<a[j]中ans+=mid-i+1就可以了,说明a[j]比区间[i,mid]中的任何一个元素都要小,而且位置又在j的前面,提供了mid-i+1个逆序对。
【代码】
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long LL; 6 7 int a[100010],c[100010]; 8 int n; 9 LL ans=0; 10 11 void merge_sort(int l,int r){ 12 int mid=(l+r)>>1,i=l,j=mid+1,k; 13 if(l>=r)return; 14 merge_sort(l,mid); 15 merge_sort(mid+1,r); 16 k=l; 17 while(i<=mid&&j<=r){ 18 if(a[i]>a[j]){ 19 c[k++]=a[j++]; 20 ans+=mid-i+1; 21 } 22 else c[k++]=a[i++]; 23 } 24 while(i<=mid)c[k++]=a[i++]; 25 while(j<=r)c[k++]=a[j++]; 26 for(i=l;i<=r;i++) a[i]=c[i]; 27 } 28 29 int main() 30 { 31 scanf("%d",&n); 32 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 33 merge_sort(1,n); 34 printf("%lld ",ans); 35 return 0; 36 }