[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;
}

浙公网安备 33010602011771号