[bzoj1237][SCOI2008]配对

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Rose_max/article/details/82909836

Description

你有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是不允许的,因 为相同的数不许配对。

Input

第一行为一个正整数n,接下来是n 行,每行两个整数Ai和Bi,保证所有 Ai各不相同,Bi也各不相同。

Output

输出一个整数,即配对整数的差的绝对值之和的最小值。如果无法配对,输 出-1。

Sample Input

3

3 65

45 10

60 25

Sample Output

32

HINT

1 <= n <= 105,Ai和Bi均为1到106之间的整数。

题解

刷着CF刷到这个优美的结论赶快跑回来过了他…
排序后一个点i只会与与他相距不超过2的点匹配
大力dp就行了

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline void print(int x){write(x);printf(" ");}
int n,a[110000],b[110000];
LL f[110000];
void _min(LL &x,LL y){x=x<y?x:y;}
int cal(int x,int y){return abs(a[x]-b[y]);}
int main()
{
	n=read();
	for(int i=1;i<=n;i++)a[i]=read(),b[i]=read();
	sort(a+1,a+1+n);sort(b+1,b+1+n);
	memset(f,63,sizeof(f));
	f[0]=0;
	if(a[1]!=b[1])f[1]=cal(1,1);
	for(int i=2;i<=n;i++)
	{
		if(a[i]!=b[i])f[i]=f[i-1]+cal(i,i);
		if(a[i]!=b[i-1]&&a[i-1]!=b[i])_min(f[i],f[i-2]+cal(i,i-1)+cal(i-1,i));
		if(i>2&&a[i]!=b[i-1]&&a[i-1]!=b[i-2]&&a[i-2]!=b[i])_min(f[i],f[i-3]+cal(i,i-1)+cal(i-1,i-2)+cal(i-2,i));
		if(i>2&&a[i]!=b[i-2]&&a[i-1]!=b[i-1]&&a[i-2]!=b[i])_min(f[i],f[i-3]+cal(i,i-2)+cal(i-1,i-1)+cal(i-2,i));
		if(i>2&&a[i]!=b[i-2]&&a[i-1]!=b[i]&&a[i-2]!=b[i-1])_min(f[i],f[i-3]+cal(i,i-2)+cal(i-1,i)+cal(i-2,i-1));
	}
	printf("%lld\n",f[n]);
	return 0;
}```

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/82909836
今日推荐