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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值