hdu 1394 http://acm.hdu.edu.cn/showproblem.php?pid=1394 用线段树求逆序数,例如要求x的逆序数只需要访问(x+1,n)段有多少个数,就是x的逆序数。还有就是求最小逆序数的时候有个巧妙的想法,当把x放入数组的后面,此时的逆序数应该为x没放入最后面之前的逆序总数加上(n-x)再减去(x-1);sum = sum+(n-x[i])-(x[i]-1)。 线段树 #include<cstdio> #include<algorithm> #include<iostream> using namespace std; #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 const int maxn = 5555; int sum[maxn<<2]; void PushUP(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void build(int l,int r,int rt) { sum[rt] = 0; if (l == r) return ; int m = (l + r) >> 1; build(lson); build(rson); } void update(int p,int l,int r,int rt) { if (l == r) { sum[rt]++; return ; } int m=(l+r)>>1; if(p<=m) update(p,lson); else update(p,rson); PushUP(rt); } int query(int L,int R,int l,int r,int rt) { if (L <= l && r <= R) return sum[rt]; int m=(l+r)>>1; int ret = 0; if(L<=m) ret+=query(L,R,lson); if(R>m) ret+=query(L,R,rson); return ret; } int x[maxn]; int main() { int n; while(~scanf("%d",&n)) { build(0,n-1,1); int sum=0; for(int i=0;i<n;i++) { scanf("%d",&x[i]); sum+=query(x[i],n-1,0,n-1,1); update(x[i],0,n-1,1); } int ret=sum; for(int i=0;i<n;i++) { sum+=n-x[i]*2-1; ret=min(ret,sum); } printf("%d\n",ret); } return 0; } 蛮力法 #include <iostream> #include <cstdio> #include <cstdlib> #define M 5010 using namespace std; int map[M]; int n,ans,t; int main() { while(scanf("%d",&n)!=EOF) { t=0,ans=9999999; for(int i=1;i<=n;i++) scanf("%d",&map[i]); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(map[i]>map[j]) t++; cout<<t<<endl; for(int i=1;i<=n;i++) { t=t+n-map[i]*2-1; ans=min(t,ans); } printf("%d\n",ans); } return 0; }