国庆七天测(五)祭司

版权声明:写得不好,随便转载,但请注明出处,感激不尽 https://blog.csdn.net/xyc1719/article/details/82944583

【题意】给定n个数的取值范围,把他们分为a,b两组。找到一种恰当的分组使得,两个集合的差值的绝对值的最大值最小。n,li,ri<=200
【分析】首先一个显而易见的规律是,差值最大值一定是一个集合最大值减去另一个集合的最小值。这样我们可以在确定集合时O(1)出解。然后二进制枚举加玄学猴子排序就可以ac了,然而并不是正解。

考虑一种dp,定义f[i][j]为A集合中下界为i上界为j能否达到。设所有下界之和为suml,所有上界之和为sumr。B集合上下界为[suml-i,sumr-j]则差值绝对值最大值就是max(abs(suml-i-j),abs(sumr-i-j))。因为suml和sumr是常值,所以只要背包i+j的值即可。因为suml<=i+j<=sumr,所以绝对值也可以去掉。
Code:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=81000;
bool f[maxn];
int a[maxn],b[maxn],n;
int main(){
	scanf("%d",&n);
	int suma=0,sumb=0;
	for(int i=1;i<=n;i++)
		scanf("%d%d",&a[i],&b[i]),suma+=a[i],sumb+=b[i];
	f[0]=1;
	for(int i=1;i<=n;i++){
		int x=a[i]+b[i];
		for(int j=40000;j>=0;j--)
			f[j+x]=f[j+x]|f[j];
	}
	int ans=sumb;
	for(int i=0;i<=40000;i++) if(f[i]) ans=min(ans,max(sumb-i,i-suma));
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/82944583