逆序数。也就是说,对于n个不同的元素,先规定各元素之间有一个标准次序(比如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的先后次序与标准次序不同一时候,就说有1个逆序。
一个排列中全部逆序总数叫做这个排列的逆序数。
我们移动元素的次数转化为,假如对每一个数da[i]来说前面比他大的数的数目为c[i]的话。那么移动元素总次数就应该是c[0]+c[1]+……+c[n-1],就是数列的逆序数。
一般解决有两种思路。
1、归并排序,归并排的话一定是最好的方案。主观上想一下每个数都在向目标位置前进(学过数据结构的话有个名词叫稳定排序,还有一个稳定排序是冒泡,选择明显不是)。
2、用线段树树状数组来做,求逆序在还有一篇博文中有提。
复杂度来说。先说两种排序,冒泡为O(n^2),归并O(nlog(n)),树状数组也是O(nlog(n)),
代码:
#include<iostream> #include<cstdio> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<cstring> #include<algorithm> #define rep(i,a,b) for(int i=(a);i<(b);i++) #define rev(i,a,b) for(int i=(a);i>=(b);i--) #define clr(a,x) memset(a,x,sizeof a) #define inf 0x3f3f3f3f typedef long long LL; using namespace std; const int mod=1e9 +7; const int maxn=2005; const int maxm=4005; int a[maxn],tmp[maxn]; int ans; void Merge(int l,int m,int r) { int i=l; int j=m+1; int k=l; while(i<=m&&j<=r) { if(a[i]>a[j]) { tmp[k++]=a[j++]; ans+=m-i+1; } else { tmp[k++]=a[i++]; } } while(i<=m)tmp[k++]=a[i++]; while(j<=r)tmp[k++]=a[j++]; for(int i=l;i<=r;i++) a[i]=tmp[i]; } void Merge_sort(int l,int r) { if(l<r) { int m=(l+r)>>1; Merge_sort(l,m); Merge_sort(m+1,r); Merge(l,m,r); } } int main() { int t,n,cas=1; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&a[i]); ans=0; Merge_sort(0,n-1); printf("Scenario #%d: %d ",cas++,ans); } return 0; }