HDOJ 1394 Minimum Inversion Number
【题目描述】
给定一个序列a1...an,每次可以吧第一个元素放到最后形成一个新的序列,求解这n个序列中逆序数最小的一个。
【思路】
线段树的应用——利用线段树求解逆序数。
一组逆序对ai,aj满足ai>aj&&i<j,求解时先进行排序,找出没个数的相对大小。
插入的时候从最后一个开始向前一次插入,每次将x[i]插入到k时。询问1...k这段中已插入的个数。
因为1...k这段中已插入的个数即为排在x[i]之后并且比x[i]小的数的个数,即为包含x[i]的逆序对总数。
求出原序列的逆序对数之后,每次变更之后的逆序数可以提出来。
#include<cstdio> #include<algorithm> #define lson n<<1 #define rson n<<1|1 #define N 50100 using namespace std; struct{ int l,r,cnt; }s[N<<2]; int x[N]; void build(int l,int r,int n){ s[n].l=l; s[n].r=r; s[n].cnt=0; if(l==r)return; int mid=(l+r)>>1; build(l,mid,lson); build(mid+1,r,rson); } void update(int n,int k){ s[n].cnt++; if(s[n].l==s[n].r) return; int mid=(s[n].l+s[n].r)>>1; if(k<=mid) update(lson,k); else update(rson,k); } int query(int l,int r,int n){ if(s[n].l==l&&r==s[n].r) return s[n].cnt; int mid=(s[n].l+s[n].r)>>1; if(r<=mid) return query(l,r,lson); else if(l>mid) return query(l,r,rson); else return query(l,mid,lson)+query(mid+1,r,rson); } int main(){ int n; while(~scanf("%d",&n)){ int ans=0; build(1,n,1); for(int i=1;i<=n;i++) scanf("%d",&x[i]); for(int i=n;i>0;i--){ ans+=query(1,x[i]+1,1); update(1,x[i]+1); } int min=ans; for(int i=1;i<=n;i++){ ans=ans+n-2*x[i]-1; min=min<ans?min:ans; } printf("%d\n",min); } return 0; }