链接:点击打开链接
题意:给出一个序列,每次讲队首放在队尾,求这个过程中逆序数最小是多少
代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; const int SIZE=5005; int segtree[SIZE<<2]; void build(int l,int r,int rt){ int m; segtree[rt]=0; if(l==r) return ; m=(l+r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); segtree[rt]=segtree[rt<<1]+segtree[rt<<1|1]; } void update(int p,int add,int l,int r,int rt){ int m; if(l==r){ segtree[rt]=add; return ; } m=(l+r)>>1; if(p<=m) update(p,add,l,m,rt<<1); else update(p,add,m+1,r,rt<<1|1); segtree[rt]=segtree[rt<<1]+segtree[rt<<1|1]; } int query(int L,int R,int l,int r,int rt){ int m,ans; if(L<=l&&r<=R) return segtree[rt]; m=(l+r)>>1; ans=0; if(L<=m) ans+=query(L,R,l,m,rt<<1); if(R>m) ans+=query(L,R,m+1,r,rt<<1|1); return ans; } //线段树单点更新模板 int main(){ //这个题数据应该是不强,暴力找出逆序数 int n,i,j,ans,sum; //再递推出剩下的也可以 int x[5005]; while(scanf("%d",&n)!=EOF){ sum=0; build(0,n-1,1); //建树嫌麻烦的话可以直接memmset // memset(segtree,0,sizeof(segtree)); //反正刚开始整个树都是0 for(i=0;i<n;i++){ scanf("%d",&x[i]); sum+=(i-query(0,x[i],0,n-1,1)); //用i减去前面输入的比当前x[i]小的就是这位的逆序数 update(x[i],1,0,n-1,1); } ans=sum; for(i=0;i<n;i++){ sum=sum-x[i]+(n-1-x[i]); //减去原来产生的逆序数,再加上新产生的逆序数 ans=min(ans,sum); } printf("%d\n",ans); } return 0; }