题目链接:点击打开链接
先求出初始序列的逆序数,方法是把原序列每个元素存成结构体,包含数和位置,按数的大小由大到小排序,然后从最大的数开始,先查询到这个数前有多少个数,也就是这个数的逆序数,然后再更新这个数,在这个数的位置加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;
}