[NOIP2013 提高组] 火柴排队

题目描述

涵涵有两盒火柴,每盒装有 \(n\) 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为:\(\sum (a_i-b_i)^2\)

其中 \(a_i\) 表示第一列火柴中第 \(i\) 个火柴的高度,\(b_i\) 表示第二列火柴中第 \(i\) 个火柴的高度。

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

输入格式

共三行,第一行包含一个整数 \(n\),表示每盒中火柴的数目。

第二行有 \(n\) 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。

第三行有 \(n\) 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。

输出格式

一个整数,表示最少交换次数对 \(10^8-3\) 取模的结果。

样例输入 #1

4
2 3 1 4
3 2 1 4

样例输出 #1

1

样例输入 #2

4
1 3 4 2
1 7 2 4

样例输出 #2

2

样例说明

#1

最小距离是 \(0\),最少需要交换 \(1\) 次,比如:交换第 $1 $列的前 \(2\) 根火柴或者交换第 \(2\) 列的前 \(2\) 根火柴

#2

最小距离是 \(10\),最少需要交换 \(2\) 次,比如:交换第 \(1\) 列的中间 \(2\) 根火柴的位置,再交换第 \(2\) 列中后 \(2\) 根火柴的位置。

数据范围

对于 \(10\%\) 的数据, \(1 \leq n \leq 10\)

对于 \(30\%\) 的数据,\(1 \leq n \leq 100\)

对于 \(60\%\) 的数据,\(1 \leq n \leq 10^3\)

对于 \(100\%\) 的数据,\(1 \leq n \leq 10^5\)\(0 \leq\) 火柴高度 \(< 2^{31}\)

Solution:

\(设P=\sum (a_i-b_i)^2=\sum \vert a_i-b_i\vert^2\)
由上式可以得出当 \(a_i\)\(b_i\) 差距最小时,\(P\) 最小

因此,当 \(a_i\)\(b_i\) 有序时,\(P\) 最小

  • 对于 \(a\) 的每一个操作,可以一一对应到 \(b\) 的一个操作,因此只需对一个数组操作即可,最终使得 \(a_i\)\(b_i\) 保持升序时的对应位置

  • 最少操作次数:将 \(a\) 按照 \(b\) 中的大小关系排序的最少操作次数

  • \(a,b\) 离散化,\(res\) 记录每一个 \(b_i\)\(a\) 中的位置,此时 \(res\) 的逆序对就是最少操作次数

Code:

#include <cstdio>
#include <algorithm>

using namespace std;

typedef long long ll;

const int N=1e+5,mod=99999997;

int n;
int tmp[N],res[N],mp[N];
int a[N],ta[N],b[N],tb[N];

int msort(int a[],int l,int r)
{
    if(l==r)return 0;

    int mid=(l+r)>>1;
    int res=msort(a,l,mid)+msort(a,mid+1,r);

    int i=l,j=mid+1,k=0;
    while(i<=mid && j<=r)
    {
        if(a[i]<=a[j])tmp[k++]=a[i++];
        else
        {
            res=(res+mid-i+1)%mod;
            tmp[k++]=a[j++];
        }
    }
    while(i<=mid)tmp[k++]=a[i++];
    while(j<=r)tmp[k++]=a[j++];
    for(int i=l,j=0;i<=r;++i,++j)a[i]=tmp[j];
    return res;
}
int main()
{
    scanf("%d",&n);

    for(int i=1;i<=n;++i)scanf("%d",&a[i]),ta[i]=a[i];
    for(int i=1;i<=n;++i)scanf("%d",&b[i]),tb[i]=b[i];

    sort(ta+1,ta+n+1);
    sort(tb+1,tb+n+1);

    int ma=unique(ta+1,ta+n+1)-ta-1;
    int mb=unique(tb+1,tb+n+1)-tb-1;

    for(int i=1;i<=n;++i)
    {
        a[i]=lower_bound(ta+1,ta+ma+1,a[i])-ta;
        b[i]=lower_bound(tb+1,tb+mb+1,b[i])-tb;
    }

    for(int i=1;i<=n;++i)mp[a[i]]=i;
    for(int i=1;i<=n;++i)res[i]=mp[b[i]];

    printf("%d\n",msort(res,1,n));
    return 0;
}
posted @ 2022-10-07 15:23  FighterQ  阅读(50)  评论(0)    收藏  举报