题目链接:https://vjudge.net/problem/POJ-2299
题目大意:
求数列中逆序对的个数。
知识点: 归并排序
解题思路:
对于数列中的每一个逆序对,它们之间早晚都需要一次邻位变换,因此答案即为数列中逆序对的个数。
我们用归并排序求逆序对个数:对于左右两个已经排好序的子区间,在合并之前先用一种\(O(n)\)的方式计算出母区间中逆序对的个数,具体方式见代码。
AC代码:
1 #include <cstdio> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 500000+5; 5 ll a[maxn],temp[maxn]; 6 ll ans; 7 void MergeSort(int l,int r){ 8 if(l==r) return; 9 int m=(l+r)>>1; 10 MergeSort(l,m); MergeSort(m+1,r); 11 for(int i=m,j=r;i>=l&&j>=m+1;){//计算逆序对个数 12 if(a[i]>a[j]){ 13 ans+=(j-m); 14 i--; 15 } 16 else j--; 17 } 18 for(int i=l,j=m+1,ind=0;i<=m||j<=r;ind++){ 19 if(i>m) temp[ind]=a[j++]; 20 else if(j>r) temp[ind]=a[i++]; 21 else if(a[i]<a[j]) temp[ind]=a[i++]; 22 else if(a[j]<a[i]) temp[ind]=a[j++]; 23 } 24 for(int i=l,j=0;i<=r;i++,j++) a[i]=temp[j]; 25 } 26 int main(){ 27 int n; 28 while(scanf("%d",&n)==1&&n){ 29 ans=0; 30 for(int i=1;i<=n;i++) scanf("%lld",&a[i]); 31 MergeSort(1,n); 32 printf("%lld\n",ans); 33 } 34 return 0; 35 }