题目描述
题目大意:给两组数,求一种匹配方案,使得每一位的数差的绝对值之和最小,要求同样的数不能匹配,输出最小的和。每组数各不相同,无法匹配输出-1。(n<=10^5)
题解
这一看就是一道我想不出来的题。话说我的DP简直太菜了,智商简直连个小学生都不如。
首先排序,如果没有限制对齐就行了,现在虽然有限制,但是其实交换距离最多不会超过2。如果超过2肯定可以换成2以内的交换使答案更优(自己举几个栗子)。我看了别人的题解才知道这个神奇的性质的。
然后就直接枚举怎样交换,随便DP一下就行了。
告诉你个秘密,要用long long。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#define maxn 100100
#define INF 1e15
#define LL long long
using namespace std;
int n;
int a[maxn], b[maxn];
LL f[maxn];
LL Calc(int x, int y){
if(a[x] == b[y]) return INF;
return (LL)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+n+1);
sort(b+1, b+n+1);
for(int i = 1; i <= n; i++) f[i] = INF;
f[0] = 0LL;
for(int i = 1; i <= n; i++){
f[i] = f[i-1] + Calc(i, i);
if(i >= 2) f[i] = min(f[i], f[i-2] + Calc(i-1, i) + Calc(i, i-1));
if(i >= 3) f[i] = min(f[i], f[i-3] + Calc(i-2, i) + Calc(i-1, i-2) + Calc(i, i-1));
if(i >= 3) f[i] = min(f[i], f[i-3] + Calc(i-2, i-1) + Calc(i-1, i) + Calc(i, i-2));
}
if(f[n] == INF) f[n] = -1;
printf("%lld\n", f[n]);
return 0;
}