给你一段序列a1,a2,a3,a4,a5,a6,a7,,然后这段序列可以一直调动第一个数字到最后,例如:
a2,a3,a4,a5,a6,a7,a1,…………直到循环了一遍。然后从这么多的序列中求出逆序列最小的一组。
每次循环的时候都可以递归求解逆序对数:设原序列逆序数为sum, 当把原序列第一个移动到最后位置时,逆序数变为:sum = sum-(ai-1)+(n-ai);
所以只需要求最开始一段序列的逆序数,用线段树,复杂度O(NlogN)
线段树功能:update:单点增减 query:区间求和
//1120 KB 78 ms #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define root 0,n-1,1 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; #define M 5005 int sum[M<<2]; int a[M]; void pushup(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void build(int l,int r,int rt) { if(l==r){ sum[rt]=0; return; } int m=(l+r)>>1; build(lson); build(rson); pushup(rt); } int query(int L,int R,int l,int r ,int rt) { if(L<=l&&r<=R){ return sum[rt]; } int res=0; int m=(l+r)>>1; if(L<=m) res+=query(L,R,lson); if(R>m) res+=query(L,R,rson); return res; } void update(int pos,int l,int r,int rt) { //printf("l=%d,r=%d\n",l,r); if(l==r) { sum[rt]++; return ; } int m=(l+r)>>1; if(pos<=m) update(pos,lson); else update( pos, rson); pushup(rt); } int main() { int n; while(~scanf("%d",&n)){ build(root); int ans=0,minn=(1<<30); for(int i=0;i<n;i++){ scanf("%d",&a[i]); ans+=query( a[i],n-1,root); update(a[i] ,root); } for(int i=0;i<n;i++){ ans+=n-a[i]-1-a[i]; minn=min(ans,minn); } printf("%d\n",minn); } return 0; }