因为这n个数为0~n-1;
所以如果第一个数为k,那么有n-k个数比他大,k-1个数比他小,
假设现在逆序数为sum,那么第一个数的逆为0,把他放到最后时
比他小的数的逆都会少1,放到最后了这个数的逆就是比他大的数的个数为n-k
所以新的你序数sum=sum-(k-1)+n-k=sum+n-1-2*k
然后可以建一个线段树,可以查询出区间L,R中数的个数。
#include<iostream>
#include<cmath>
#include<string.h>
#include<stdio.h>
#define R(x) (x<<1|1)
#define L(x) (x<<1)
#define MAX 5010
using namespace std;
int x[MAX];
struct node
{
int l,r,len;
}a[3*MAX];
void build(int t,int l,int r)
{
a[t].l=l;
a[t].r=r;
a[t].len=0;
if(l==r)return ;
int mid=(l+r)/2;
build(L(t),l,mid);
build(R(t),mid+1,r);
}
void update(int t,int l,int r)
{
if(a[t].l>=l&&a[t].r<=r)
{
a[t].len++;
return ;
}
if(a[t].l==a[t].r)return ;
int mid=(a[t].l+a[t].r)/2;
if(a[t].l<=mid)
update(L(t),l,r);
if(a[t].r>mid)
update(R(t),l,r);
a[t].len=a[L(t)].len+a[R(t)].len;
}
int query(int t,int l,int r)
{
if(a[t].l>=l&&a[t].r<=r)
{
return a[t].len;
}
if(a[t].l==a[t].r)return 0;
int mid=(a[t].l+a[t].r)/2;
int ll=0;
if(a[t].l<=mid)
ll+=query(L(t),l,r);
if(a[t].r>mid)
ll+=query(R(t),l,r);
return ll;
}
int main()
{
int n,i,maxval,ans;
while(scanf("%d",&n)!=EOF)
{
ans=0;
build(1,0,n);
for(i=0;i<n;i++)
{
scanf("%d",&x[i]);
ans+=query(1,x[i]+1,n);
update(1,x[i],x[i]);
}
maxval=ans;
for(i=0;i<n;i++)
{
ans=ans+n-1-2*x[i];
maxval=min(maxval,ans);
}
printf("%d\n",maxval);
}
}