题意就是给一个1到n的排列,然后要你把这个排列变成一个好排列,(好排列的定义是这样的,k+1,k+2,...,n,1,...,k k+1取值从1变化到n),每次操作是交换两个相邻的数,问最小交换次数。
很显然我们需要把原排列转换成n个好排列的最小交换次数都求出来,然后取最小值。显然变成1 2 3 4 。。。n 这个排列的最小交换次数就是原排列的逆序对数,然后2 3 4。。。。n 1 这个排列的最小交换次数就可以通过1 2 3 4 。。。n 的最小交换次数递推得到。可以这样想,1 2 3 4 。。。n 就是把原排列里的1放到最前面的位置,然后调整2 3 4 。 。。n的相对位置, 2 3 4。。。。n 1 就是把1放到最后的位置,然后调整2 3 4 。。。n的相对位置, 2 3 4。。。。n 1的花费减去 1 2 3 4 。。。n的花费就是对1的摆放的花费的差值即n-pos[1]-(pos[1]-1),那么 2 3 4。。。。n 1的花费=1 2 3 4 。。。n 的花费+n-pos[1]-(pos[1]-1)。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+10;
int a[maxn],c[maxn],pos[maxn],n;
ll ans;
inline void msort(int l,int r)
{
if(l==r)return;
int mid=(l+r)>>1;
msort(l,mid);msort(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r){
if(a[i]<=a[j])
c[k++]=a[i++];
else{
c[k++]=a[j++];
ans+=1LL*(mid-i+1);
}
}
while(i<=mid)c[k++]=a[i++];
while(j<=r)c[k++]=a[j++];
for(i=l;i<=r;i++)
a[i]=c[i];
}
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
int main()
{
int t;
ll tmp;
t=read();
while(t--)
{
ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
a[i]=read(),pos[a[i]]=i;
msort(1,n);
tmp=ans;
for(int i=2;i<=n;i++)
{
tmp=tmp+1LL*(n-pos[i-1]-(pos[i-1]-1));
ans=min(ans,tmp);
}
printf("%lld\n",ans);
}
return 0;
}