帮挂科
Time Limit: 2000/1000ms (Java/Others) 64bit IO Format: %lld & %llu
Problem Description:
冬瓜发现期末很多人都挂了线代,他决定写个程序帮挂科的同学。在一个排列中,如果一对数的前后位置与大小 顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。 可是冬瓜想的头发都掉光了,聪明的你肯定能够帮帮他。
Input:
输入有多组 第1行:N,N为序列的长度(n <= 50000) 第2 - N + 1行:序列中的元素(0 <= A[i] <= 10^9)
Output:
输出逆序数
Sample Input:
4 2 4 3 1
Sample Output:
4
解题思路:这里用归并排序求逆序数。主要是将序列分成两部分,只要在有序的前半部分中找到的下标i比后半部分下标j大,那么下标i~m都可以构成逆序数对,即有(m-i+1)对,再合并子序列即可。。。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=50005; 4 int ans,n,a[N],tmp[N];//tmp是临时数组 5 void _merge(int l,int m,int r)//合并子序列 6 { 7 int i=l,j=m+1,k=l; 8 while(i<=m && j<=r){ 9 if(a[i]>a[j]){ 10 tmp[k++]=a[j++]; 11 ans+=m-i+1;//只要a[i]>a[j],i~m都可以构成逆序数 12 } 13 else tmp[k++]=a[i++];//相等的就直接存放到临时数组 14 } 15 while(i<=m)tmp[k++]=a[i++];//剩余的直接拷贝 16 while(j<=r)tmp[k++]=a[j++]; 17 for(int i=l;i<=r;++i) 18 a[i]=tmp[i];//临时数组赋值给a数组 19 } 20 void _merge_sort(int l,int r)//归并排序 21 { 22 if(l<r){ 23 int m=(l+r)>>1;//分成两部分 24 _merge_sort(l,m);//左递归 25 _merge_sort(m+1,r);//右递归 26 _merge(l,m,r);//合并两部分 27 } 28 } 29 int main() 30 { 31 while(cin>>n){ 32 for(int i=0;i<n;++i) 33 cin>>a[i]; 34 ans=0; 35 _merge_sort(0,n-1); 36 cout<<ans<<endl; 37 } 38 return 0; 39 }