题意:
给你N个数是0~N-1,要求统计它的所有形式的逆序对的最小值。它的所有形式的意思是,不断将数组开头的第一个数放到数组的最后面。
分析:
注意到给出的数是0~N-1,那么对于第一个数的逆序对个数就是a[1]个。
若将第一个数放到数组最后,那么逆序对将减少a[1]个,增加N-a[1]-1个。
所以我们只要预处理出一开始数列的逆序对个数再一个一个将数放到队尾即可。
代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int N=100100;
int a[N],n,m,ans,tot,sum;
struct tree{int l,r,sum;}g[N];
void build(int rt,int l,int r)
{
g[rt].l=l;
g[rt].r=r;
g[rt].sum=0;
if (l==r) return;
int mid=(l+r)/2;
build(2*rt,l,mid);
build(2*rt+1,mid+1,r);
}
void update(int rt,int k)
{
int l=g[rt].l,r=g[rt].r;
if (l==r) g[rt].sum++; else
{
int mid=(l+r)/2;
if (k<=mid)
update(2*rt,k); else
update(2*rt+1,k);
g[rt].sum=g[2*rt].sum+g[2*rt+1].sum;
}
}
int query(int rt,int ll,int rr)
{
int l=g[rt].l,r=g[rt].r;
if (ll<=l && r<=rr) return g[rt].sum;
int mid=(l+r)/2,suml,sumr;
if (ll<=mid) suml=query(2*rt,ll,rr);
if (rr> mid) sumr=query(2*rt+1,ll,rr);
return suml+sumr;
}
int main()
{
while (~scanf("%d",&n))
{
sum=0;
build(1,0,n-1);
for (int i=1;i<=n;i++)
{
scanf("%d",a+i);
update(1,a[i]);
if (a[i]!=n-1)
sum+=query(1,a[i]+1,n-1);
}
ans=sum;
for (int i=1;i<=n;i++)
{
sum+=n-a[i]-1-a[i];
if (ans>sum) ans=sum;
}
printf("%d\n",ans);
}
return 0;
}