hdu 1394 Minimum Inversion Number
题意:给出n个数,0<=k<=n-1,每次将第一个数放到最后,求最小的逆序数
分析:每次将开头的数num[i]放到最后,后面比num[i]小的数有num[i]个,所以减少num[i]个逆序数对,num[i[放到最后,前面比它大的数有n-1-num[i]个,所以每次操作后,当前的逆序数ans+n-2*num[i]-1,就是所要的结果。
可能有的人不能明白如何用线段树求开始的逆序数,这又一组测试数据,相信你按照我的程序走一圈,就能明白其中的过程
4
0 2 1 3
输出
1
代码
#include<stdio.h> #define mid int m=(l+r)>>1 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn=5555; int sum[maxn<<2]; int num[maxn]; void pushup(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void build(int l,int r,int rt) { sum[rt]=0; if(l==r) return ; mid; build(lson); build(rson); } void update(int p,int l,int r,int rt) { if(l==r) { sum[rt]++; return ; } mid; if(p<=m) update(p,lson); else update(p,rson); pushup(rt); } int query(int L,int R,int l,int r,int rt) { if(L<=l&&R>=r) return sum[rt]; mid; int ans=0; if(L<=m) ans+=query(L,R,lson); if(R>m) ans+=query(L,R,rson); return ans; } int main() { int n; while(~scanf("%d",&n)) { build(0,n-1,1); int ans=0; for(int i=0;i<n;i++) { scanf("%d",&num[i]); ans+=query(num[i],n-1,0,n-1,1); update(num[i],0,n-1,1); } int t=ans; for(int i=0;i<n;i++) { t+=n-2*num[i]-1; if(ans>t) ans=t; } printf("%d\n",ans); } return 0; }