hdu-1394 Minimum Inversion Number

题目链接

题目大意
给出一个 n 个元素的序列,每次把第一个元素放到最后面,每次都求逆序对,输出逆序对的最小值。

题解
很容易发现从第二次开始的每次的逆序对可以在上一次的逆序对的基础上修正得来。
统计 大于 和 小于 每个元素的 元素个数。
当我们把当前第一个元素放到最后面时,答案的变化:减去小于它的个数 再加上大于它的个数(why分两种?)1
(详解,懂的跳过。由于它是第一个,所以每个小于它的都和它组成一个逆序对,当它变为最后一个元素时,这些逆序对都木有了。但是所有比它大的就会和它形成逆序对)

具体实现,首先用二路归并刷出第一次的解,顺便排序,然后去重(也可以不去重,那么二分时要小心),二分查找,找到的位置为 x ,比它小的有 x-1 个,比它大的有 n-x 个。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=5005;
int n,m,ans,sum,a[maxn],b[maxn],c[maxn],DY[maxn],XY[maxn];
int fin(int x)
{
    for (int L=1,R=m,mid=L+R>>1;L<=R;mid=L+R>>1)
      if (x>b[mid]) L=mid+1;else
      if (x<b[mid]) R=mid-1;else
      return mid;
}
void msort(int L,int R)
{
    if (L>=R) return;
    int mid=L+R>>1,i=L,j=mid+1;
    msort(L,mid);msort(mid+1,R);
    for (int k=L;k<=R;k++) c[k]=b[k];
    for (int k=L;k<=R;k++)
      if (i<=mid&&(j>R||c[i]<=c[j])) b[k]=c[i++];
      else b[k]=c[j++],sum+=mid+1-i;
}
void work()
{
    sum=m=0;
    memset(XY,0,sizeof XY);
    memset(DY,0,sizeof DY);
    for (int i=1;i<=n;i++) scanf("%d",a+i),b[i]=a[i];
    msort(1,n);m=0;ans=sum;
    for (int i=1;i<=n;i++)
      if (b[i]!=b[i+1]) b[++m]=b[i];
    for (int i=1;i<=n;i++)
    {
        int x=fin(a[i]);
        XY[i]=x-1;DY[i]=n-x;
    }
    for (int i=1;i<=n;i++)
    {
        sum-=XY[i]-DY[i];
        if (sum<ans) ans=sum;
    }
    printf("%d\n",ans);
}
int main()
{
    while (~scanf("%d",&n)) work();
    return 0;
}

  1. 题目给出的逆序对定义中,a[i]>a[j] 且 i

猜你喜欢

转载自blog.csdn.net/xu0_zy/article/details/80290024