题目背景
四川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:
3
3 65
45 10
60 25
输出样例#1:
32
输入样例#2:
3
5 5
6 7
8 8
输出样例#2:
5
说明
30%的数据满足:n <= 104
100%的数据满足:1 <= n <= 105,Ai和Bi均为1到106之间的整数。
思路:
这道题需要知道一个类似结论的东西:将A,B排序,每个位置与他配对的位置距离不会超过2.
具体的证明我也不会不过可以感性的理解一下。
假设没有不允许相同的数配对这个限制,那么最优的决策就是分别排序后相同位置的数配对。
现在有了限制,我们就需要交换一下配对,交换的越多和会越大,所以一定是尽可能隔着比较近的数进行交换。
如果相邻两个都与同位置的相同,那么可以使他们交换一下。
如果相邻的三个位置都相同,可以三个人换一下。最多三个一定可以存在合法的交换方案。数量再多就可以拆分。
知道了这就可以DP一下。
四种情况分类讨论一下就可以了。
错因:
1.抬头,看见上面的数据范围了吗?我一直以为是105和106结果一直RE,结果是10^5。
2.最大值竟然那么大,0x7f7f7f7f竟然取小了。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n; int a[100005],b[100005]; long long f[100005]; long long col(int x,int y){ if(a[x]==b[y]) return 0x7f7f7f7f7f; else return abs(a[x]-b[y]); } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]); sort(a+1,a+1+n); sort(b+1,b+1+n); for(int i=0;i<=n;i++) f[i]=0x7f7f7f7f7f; f[0]=0; for(int i=1;i<=n;i++){ if(i>=1) f[i]=min(f[i],f[i-1]+col(i,i)); if(i>=2) f[i]=min(f[i],f[i-2]+col(i,i-1)+col(i-1,i)); if(i>=3) f[i]=min(f[i],f[i-3]+col(i,i-1)+col(i-1,i-2)+col(i-2,i)); f[i]=min(f[i],f[i-3]+col(i-2,i-1)+col(i-1,i)+col(i,i-2)); } cout<<f[n]; }