题意:
有一个n个整数的排列,这n个整数就是0,1,2,3...n-1这n个数(但不一定按这个顺序给出)。现在先计算一下初始排列的逆序数,然后把第一个元素a1放到an后面去,形成新排列a2 a3 a4...an a1,然后再求这个排列的逆序数。继续执行类似操作(一共要执行n-1次)直到产生排列an a1 a2...an-1为止。计算上述所有排列的逆序数,输出最小逆序数。
题解:
对于原始数列,易用树状数组计算出序列的逆序数。设序列中比a1小的个数为x,比a1大的个数为y,所以将a1移动至最后形成的序列相比较原来的数列,增加了y,减少了x。所以每次移动都是原来的加上y-x即可。有y+x+1=n。可得y-x = n+1-2*a1.
#include<bits/stdc++.h> using namespace std; const int maxn = 5000+10; int c[maxn]; int lowbit(int x) { return x & -x; } int sum(int x) { int res=0; while(x>0) { res += c[x]; x -= lowbit(x); } return res; } void add(int x,int v) { while(x<maxn) { c[x]+=v; x += lowbit(x); } } int a[maxn]; int main() { int n; while(cin>>n) { int cnt=0; memset(c,0,sizeof c); for(int i=1;i<=n;i++) { scanf("%d",a+i); a[i]++; cnt+=i-1-sum(a[i]); add(a[i],1); } int ans=cnt;///排列的逆序数 for(int i=1;i<n;i++) { cnt += n+1-2*a[i]; ///每次移动 ans = min(ans,cnt); } cout<<ans<<endl; } }