1A...火车上写的,,,
学到:
1、明确特征,分类讨论,可以防止计数重复
求逆序数的时候,算出以每个数为逆序数对的第二个数的情况之和即为序列的逆序数,这样可以防止重复
2、如果没有思路,就先从若干情况入手,自己模拟试试,找规律
这道题的规律就是,假设所有比x[i]小的数个数为c,那么当把第一个数移到序列最后,产生的新的逆序对个数为sum=sum-c+n-1-c;,减少了c,增加了n-1-c
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define lson(i) l,mid,(i)*2 #define rson(i) mid+1,r,((i)*2+1) #define ll rt*2 #define rr (rt*2+1) const int MAXN = 5000+10; struct Node{int l,r,tot;}nodes[MAXN*4]; int x[MAXN],n,d[MAXN],y[MAXN]; void Pushup(int rt) { nodes[rt].tot = nodes[ll].tot + nodes[rr].tot; } void build(int rt, int l, int r) { nodes[rt].l=l; nodes[rt].r=r; nodes[rt].tot=0; if(l == r) { return; } int mid=(l+r)/2; build(ll,l,mid); build(rr,mid+1,r); } void Update(int rt, int p, int v) { if(nodes[rt].l == nodes[rt].r) { nodes[rt].tot=1; return; } int mid=(nodes[rt].l+nodes[rt].r)/2; if(p<=mid) { Update(rt*2,p,v); } else { Update(rr,p,v); } Pushup(rt); } int Query(int rt, int l, int r) { if(l == nodes[rt].l && r == nodes[rt].r) { return nodes[rt].tot; } int mid=(nodes[rt].l+nodes[rt].r)>>1; if(r<=mid)return Query(ll,l,r); else { if(l>mid) { return Query(rr,l,r); } else { return Query(ll,l,mid)+Query(rr,mid+1,r); } } } int main() { freopen("hdu1394.txt","r",stdin); while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) { scanf("%d",&x[i]); x[i]+=1; } build(1,1,n); for(int i=1;i<=n;i++) { Update(1,x[i],1); d[i]=Query(1,1,x[i])-1; } int sum=0,ans=n; for(int i=1;i<=n;i++) { y[i]=Query(1,1,x[i])-1-d[i];//y[i] x[i]右侧比之小的数个数 sum+=(i-1-d[i]); } ///////////////////////// /* for(int i=1;i<=n;i++) { printf("i=%d d=%d y=%d\n",i,d[i],y[i]); } printf("sum=%d\n",sum);*/ ////////////// int c; ans=sum; for(int i=1;i<=n;i++) { c=y[i]+d[i]; sum=sum-c+n-1-c; ans=min(ans,sum); } printf("%d\n",ans); } return 0; }
原文:http://blog.csdn.net/u011026968/article/details/38109211