给出一列数,可以按照循环移位的方式改变它们的顺序,求他们的最小逆序数。
可以用线段树或者树状数组来求最开始的逆序数,得到之后可以推出剩下的所有的逆序数,求min就可以了。对于某一序列,其中的某一个数a[i]能构成多少个逆序,只须判断在x[i]+1~n的范围内找之前的数是否出现过的次数;由第一个序列的逆序数可以推出它下一个序列的逆序数。 有规律 下一个序列的逆序数 sum = sum + n - x[i] - 1 - x[i];
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 5555;
using namespace std;
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 = (r+l)>>1;
build(lson);
build(rson);
}
void update(int p,int l , int r, int rt)
{
if(l == r)
{
sum[rt] = 1;
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 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;
}
int main()
{
int n , x[maxn],sum ;
while(~scanf("%d",&n))
{
build(0,n-1,1);
sum = 0;
for(int i = 1 ; 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 res = sum;//逆序数
for(int i = 1 ; i <= n ; i++)//求所有的逆序数
{
sum += n - x[i] - x[i] - 1;
res = min(sum,res);
}
printf("%d\n",res);
}
return 0;
}