可以不断将尾部移动到头部,求最小逆序数。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=5005;
int n, a[maxn];
struct node{
int lef, rig, mid, cover;
}seg[maxn*4];
void make_tree(int num, int lef, int rig){
seg[num].lef=lef;
seg[num].rig=rig;
seg[num].cover=0;
seg[num].mid=(lef+rig)/2;
if(lef+1!=rig){
make_tree(num*2, lef, seg[num].mid);
make_tree(num*2+1, seg[num].mid, rig);
}
}
void update(int num, int lef, int rig, int cover){
if(seg[num].lef==lef&&seg[num].rig==rig){
seg[num].cover+=cover;
return;
}
seg[num].cover+=cover;
if(rig<=seg[num].mid)
update(2*num, lef, rig, cover);
else if(lef>=seg[num].mid)
update(2*num+1, lef, rig, cover);
else {
update(2*num, lef, seg[num].mid, cover);
update(2*num+1, seg[num].mid, rig, cover);
}
}
int cal(int num, int lef, int rig){
if(seg[num].lef==lef&&seg[num].rig==rig){
return seg[num].cover;
}
if(rig<=seg[num].mid)
return cal(2*num, lef, rig);
else if(lef>=seg[num].mid)
return cal(2*num+1, lef, rig);
else return cal(2*num, lef, seg[num].mid)+cal(2*num+1, seg[num].mid, rig);
}
int main(){
//freopen("1.txt", "r", stdin);
int t, i, ans;
while(scanf("%d", &n)!=EOF){
make_tree(1, 0, n+1);
for(i=1; i<=n; i++){
scanf("%d", &a[i]);
}
update(1, a[n], a[n]+1, 1);
t=0;
for(i=n-1; i>=1; i--){
update(1, a[i], a[i]+1, 1);
t+=cal(1, 0, a[i]);
}
ans=t;
for(i=1; i<n; i++){
t=t+n-2*a[i]-1;
if(t<ans)ans=t;
}
printf("%d\n", ans);
}
return 0;
}