10 1 3 6 9 0 8 5 7 4 2
16
做这个题首先要能百度到这个东西:将序列中某一个数放到最后的逆序数改变量:n-2*a[i]-1;至于推导过程,呵呵哒就好~
思路:5000个数,多次查找当前数据前边有多少个数比他大,所以这里相当于多次询问过程,所以暴力过基本上是一定会超时的。
解法:线段树/树状数组求出当前序列的逆序数,然后根据百度到的这个结论解出最终解:
每一次输入一个数的时候、query一下前边有多少个数大于他,然后update它,搞定~
#include<stdio.h> #include<string.h> using namespace std; #define lson l,m,rt*2 #define rson m+1,r,rt*2+1 int tree[21212121]; void pushup(int rt) { tree[rt]=tree[rt<<1]+tree[rt<<1|1]; } void build( int l ,int r , int rt ) { if( l == r ) { tree[rt]=0; return ; } else { 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 tree[rt]; } else { int m=(l+r)>>1; int ans=0; if(L<=m) { ans+=Query(L,R,lson); } if(m<R) { ans+=Query(L,R,rson); } return ans; } } void update(int p,int l,int r,int rt) { if(l==r) { tree[rt]=1; return ; } else { int m=(l+r)/2; if(p<=m)update(p,lson); else update(p,rson); pushup(rt); } } int main() { int n; while(~scanf("%d",&n)) { build(1,n,1); int s[100000]; int sum=0; for(int i=0;i<n;i++) { scanf("%d",&s[i]); sum+=Query(s[i]+1,n,1,n,1); update(s[i]+1,1,n,1); } //printf("%d\n",sum); int minn=sum; for(int i=0;i<n;i++) { sum=sum+n-2*s[i]-1; if(sum<minn)minn=sum; } printf("%d\n",minn); } }