ZOJ Monthly, June 2018 J

  题意就是给一个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
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/eason9906/p/11754788.html