给n个数组成的序列,由0~n-1构成。每次把第一个数移动到最后一个数,可以形成一个新的序列。总共可形成n个序列,求这n个序列中最小的逆序数。
先求原始序列的逆序数个数:每输入一个数,统计其之前的比它大的数的个数。这里用线段树记录区间内数的个数。
对于每一个数,将其挪到后面之后,新的序列的逆序数个数=原序列逆序数个数-比该数小的数个数+比该数大的数的个数。
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define maxn 5005 #define lson i<<1,l,m #define rson i<<1|1,m+1,r int sum[maxn<<2],x[maxn]; void PushUp(int i) { sum[i]=sum[i<<1]+sum[i<<1|1]; } void build(int i,int l,int r) { sum[i]=0; if(l==r) return; int m=(l+r)>>1; build(lson); build(rson); } void update(int num,int i,int l,int r) { if(l==r) {sum[i]++;return;} int m=(l+r)>>1; if(num<=m) update(num,lson); else update(num,rson); PushUp(i); } int query(int L,int R,int i,int l,int r) { if(L<=l&&r<=R) return sum[i]; int m=(l+r)>>1; 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,i; while(~scanf("%d",&n)) { build(1,0,n-1); int s=0; for(i=0;i<n;++i) { scanf("%d",&x[i]); s+=query(x[i],n-1,1,0,n-1); update(x[i],1,0,n-1); } int ans=s; for(i=0;i<n;++i) { s=s-x[i]+n-x[i]-1; ans=min(ans,s); } printf("%d\n",ans); } return 0; }