题目链接:点击打开链接
先求出初始序列的逆序数,方法是把原序列每个元素存成结构体,包含数和位置,按数的大小由大到小排序,然后从最大的数开始,先查询到这个数前有多少个数,也就是这个数的逆序数,然后再更新这个数,在这个数的位置加1。
本题数字是不重复的且刚好是0—n-1,可以这么做,如果数有重复的,就需要开始时按从小到大排序,然后用每个数的位置减去之前有几个数就是这个数的逆序数。
代码:
#include <iostream> #include <cstdio> #include <algorithm> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; int sum[20010]; struct note{ int ord,num; }p[5010]; int k[5010]; 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 add(int p,int l,int r,int rt){ if(l==r){ sum[rt]++; return ; } int m=(l+r)>>1; if(p<=m){ add(p,lson); } else add(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 res=0; int m=(l+r)>>1; if(L<=m) res+=query(L,R,lson); if(R>m) res+=query(L,R,rson); return res; } bool cmp(note a,note b){ return a.num>b.num; } int main(){ int n; while(cin>>n){ for(int i=1;i<=n;i++){ scanf("%d",&k[i]); p[i].num=k[i]; p[i].ord=i; } sort(p+1,p+n+1,cmp); build(1,n,1); int cur=0; for(int i=1;i<=n;i++){ cur+=query(1,p[i].ord,1,n,1); add(p[i].ord,1,n,1); } int res=cur; for(int i=1;i<=n;i++){ cur=cur+n-k[i]*2-1; res=min(res,cur); } printf("%d\n",res); } return 0; }