/*思路: 求逆序数: 树状数组解决:就是逆向扫描原序列,扫描到a[i]时,累加在其后面a[i+1..N]中 小于它的个数 = sum(a[i]-1); 树状数组中逆向插入元素,当插入p[i]时,明显与它构成逆序数对的数量就等于树状数组[1..p[i]-1]这个区间的和 循环轮换的可以用数学方法O(1)求出. 单个case时间复杂度: O(NlogN)*/ #include<cstdio> #include<cstring> #include<iostream> #include<string> using namespace std; int n; int a[5010],p[5010];//a树状数组 int lowb(int t) {return t&(-t);} void add(int i,int v){ for(;i<=n;a[i]+=v,i+=lowb(i)); } int sum(int i){ int s=0; for(;i>0;s+=a[i],i-=lowb(i)); return s; } int main(){ while(~scanf("%d",&n)){ memset(a,0,sizeof(a)); memset(p,0,sizeof(p)); for(int i=1;i<=n;i++){ scanf("%d",&p[i]); p[i]++;//原数列由0开始,而树状数组只能由1开始 } int ans=0; for(int i=n;i>=1;i--){ add(p[i],1); ans+=sum(p[i]-1); }//向树状数组中逆向插入元素,当插入val[i]时, //明显与它构成逆序数对的数量就等于树状数组[1..val[i]-1]这个区间的和 int tmp=ans; for(int i=1;i<n;i++){//通过数学方法求出余下的逆序数 tmp=tmp-(p[i]-1)+(n-p[i]); if(tmp<ans) ans=tmp; } cout<<ans<<endl; } return 0; }