题意,给出一段序列,并将序列前的n-1个数字一次放到序列后面,形成新序列,并求出所有序列中的最小逆序数,可用枚举法和线段树解题
事实上,只需求出一段序列的逆序数即可推出另一段的如序列a0a1…an-1是由0到n-1组成的序列,把a0调到后面,则减少的逆序数为a0个,增加 n-1-a0个
#include <iostream>
using namespace std;//线段树求逆序数
const int k=5500;
struct node{ int left,right,num;
} tree[4*k];
void build(int left,int right ,int node)
{
tree[node].left=left;
tree[node].right=right;
tree[node].num=0;
if(left==right)
return;
int mid=(left+right)>>1;
build(left,mid,node<<1);
build(mid+1,right,node<<1|1);
}
int search(int left,int right,int node)
{
if(tree[node].left==left&&tree[node].right==right)
return tree[node].num;
int mid=(tree[node].left+tree[node].right)>>1;
if(right<=mid) return search( left,right,node<<1);
else if(left>mid) return search( left,right,node<<1|1 );
else return search( left,mid,node<<1)+search( mid+1,right,node<<1|1 );
}
void new_ (int x,int b)
{
if(tree[b].left==tree[b].right){ tree[b].num++; return ;}
int mid=(tree[b]. left+tree[b].right)>>1;
if( x<=mid ) new_(x,b<<1);
else new_(x,b<<1|1);
tree[b].num=tree[b<<1].num+tree[b<<1|1].num;
}
int main() {
int a[k];
int n,min;
while(cin>>n)
{
build(0,n-1,1);
for(int i=0;i<n;i++)
{ cin>>a[i];
}
int sum=0;
for(int i=0;i<n;i++)
{ sum+=search(a[i],n-1,1);
new_(a[i],1);
}
min=sum;
for(int i=0;i<n-1;i++)
{ sum=sum-a[i]+n-a[i]-1;
if(min>sum) min=sum;
}
cout<<min<<endl;
}
return 0;
}