【noip 2013】火柴排队

离noip2017还有99天了,开个博客记录一下,不要让自己颓废

题目描述

涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2 其中 ai 表示第一列火柴中第 i 个火柴的高度,bi表示第二列火柴中第 i 个火柴的高度。

每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对99,999,997 取模的结果。

输入格式:

共三行,第一行包含一个整数 n,表示每盒中火柴的数目。 第二行有 n 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。 第三行有 n 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。

输出格式:

输出共一行,包含一个整数,表示最少交换次数对 99,999,997 取模的结果。

数据范围:

对于 100%的数据,1 ≤ n ≤ 100,000,0 ≤火柴高度≤ maxlongint

这道题洛谷评为提高+/省选-,我觉得还是略水(虽然我只是一个学了几个月编程的蒟蒻),比起别的题目来说这道题还是比较好想的。

首先,什么状态下火柴距离最小?我第一反应就是如果a列第i高的火柴和b列第i高的火柴一一对应,这时距离应该是最小的。因为我很菜,所以一时半会没想出来证明方法。但按照“两数和相等差越小积越大”这种感觉应该是对的(领会精神….)。

然后,问题就来到了如何用最少的交换次数达到高度排名的一一对应?显然,如果以第一列火柴为标准,那么我们可以只交换第二列火柴达到目的。有一点冒泡排序的味道,而冒泡排序可以…对!求逆序对!如果对第二列火柴进行编号,问题就转化为求第二列火柴高度排名的逆序对的个数,用归并排序就可以解决因为我不会用树状数组求.

问题是,怎样重新编号?思考之后,我发现问题的本质就是要找b列火柴中的哪一根与a列火柴的哪一根在各自队伍中的排名相同,那么就给这两根火柴相同的编号i,i是该火柴在a列火柴中的位置。现在问题就变得明了了,要求排名相同的火柴,我们只需要排序,并开一个结构体记录火柴本来的位置,就解决了问题。
代码如下:

#include
#include
#include
using namespace std;
struct node{
    int ind;
    long long h;
}a[100001],b[100001];
int ans=0;
int c[100001];
int tmp[100001];
const int mod=99999997;
bool cmp(node a,node b)
{
    return a.hlong long read()
{
    long long x=0;
    char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x;
}
void msort(int l,int r)
{
    if(l==r) return ;
    int mid=(l+r)/2;
    msort(l,mid);
    msort(mid+1,r);
    int i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r)
    {
        if(c[i]<=c[j]) tmp[k++]=c[i++];
        else
        {
            tmp[k++]=c[j++];
            ans+=mid-i+1;
            ans%=mod;
        }
    }
    while(i<=mid) tmp[k++]=c[i++];
    while(j<=r) tmp[k++]=c[j++];
    for(int i=l;i<=r;i++)
        c[i]=tmp[i];
}
int main()
{
    int n;
    n=read();
    for(int i=1;i<=n;i++)
    {
        a[i].h=read();
        a[i].ind=i;
    }
    for(int i=1;i<=n;i++)
    {
        b[i].h=read();
        b[i].ind=i;
    }
    sort(a+1,a+n+1,cmp);
    sort(b+1,b+n+1,cmp);
    for(int i=1;i<=n;i++)
        c[b[i].ind]=a[i].ind;
    msort(1,n);
    printf("%d",ans%mod);
    return 0;
}

你可能感兴趣的:(solution)