[SCOI2008]配对
题目背景
四川NOI2008省选
题目描述
你有 n 个整数Ai和n 个整数Bi。你需要把它们配对,即每个Ai恰好对应一个Bp[i]。要求所有配对的整数差的绝对值之和尽量小,但不允许两个相同的数配对。例如A={5,6,8},B={5,7,8},则最优配对方案是5ó8, 6ó5, 8ó7,配对整数的差的绝对值分别为2, 2, 1,和为5。注意,5ó5,6ó7,8ó8是不允许的,因为相同的数不许配对。
输入输出格式
输入格式:
第一行为一个正整数n,接下来是n 行,每行两个整数Ai和Bi,保证所有
Ai各不相同,Bi也各不相同。
输出格式:
输出一个整数,即配对整数的差的绝对值之和的最小值。如果无法配对,输
出-1。
输入输出样例
输入样例#1:
33 6545 1060 25
输出样例#1:
32
输入样例#2:
35 56 78 8
输出样例#2:
5
说明
30%的数据满足:n <= 10^4
100%的数据满足:1 <= n <= 10^5,Ai和Bi均为1到10^6之间的整数。
题解:
如果没有整数不能匹配的要求,那么答案就是排序后一一对应的答案。
而如果连着两个数相等的话可以与旁边的数进行交换后匹配。
对于连着三个数相等的情况的话有两种交换方法:
分类讨论后转移即可。
代码:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int max_n = 1e5+7;
const LL inf = 1e15+7;
int a[max_n],b[max_n];
LL f[max_n];
int n,ans;
inline LL num(int x,int y)
{
if(a[x]==b[y]) return inf;
else return abs(a[x]-b[y]);
}
inline void dp()
{
for(int i=1; i<=n; ++i)
f[i]=inf;
f[0]=0;
for(int i=1; i<=n; ++i)
{
if(i>=1) f[i]=min(f[i],f[i-1]+num(i,i));
if(i>=2) f[i]=min(f[i],f[i-2]+num(i-1,i)+num(i,i-1));
if(i>=3) f[i]=min(f[i],min(f[i-3]+num(i-2,i)+num(i-1,i-2)+num(i,i-1),f[i-3]+num(i-2,i-1)+num(i-1,i)+num(i,i-2)));
}
}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; ++i)
scanf("%d%d",&a[i],&b[i]);
sort(a+1,a+n+1);
sort(b+1,b+n+1);
dp();
printf("%lld\n",f[n]);
return 0;
}