[BZOJ2064] 分裂

BZOJ2064 分裂

题面感人。。。
可以发现的是如果把所有的数先合起来,再把他们分开,这样是\(ans\)的上界,是\(n+m-2\)
现在我们把之前的国家面积视作\(+\),之后的国家面积视作\(-\),就会发现如果有一个子集的sum=0,就说明我们可以让这个子集内部操作。
假设这个子集有\(k\)个数,它的操作次数是\(k-2\),假设总共有\(n\)个数,操作次数就变成了
\(n-k-2+k-2=n-4\)
就可以发现如果将\(x\)视作\(\text{相等的子集数}\)\(n\)视作\(\text{元素个数}\),则\(ans=n-2x\)
因为\(n\)非常小,只有\(20\),所以可以状压\(DP\)
(把所有的字母都扩起来好鬼畜。。。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int n,m,sum[1<<20],f[1<<20];
int main() {
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&sum[1<<i-1]);
	scanf("%d",&m);
	for(int i=1;i<=m;i++) scanf("%d",&sum[1<<i+n-1]),sum[1<<i+n-1]=-sum[1<<i+n-1];
	n+=m;
	for(int i=1;i<(1<<n);i++) {
		sum[i]=sum[i^(i&-i)]+sum[i&-i];
		for(int j=0;j<n;j++) if((i&(1<<j))) f[i]=max(f[i],f[i^(1<<j)]);
		f[i]+=sum[i]==0;
	}
	cout<<n-f[(1<<n)-1]*2;
	return 0;
}
posted @ 2018-10-18 16:33  SWHsz  阅读(124)  评论(0编辑  收藏  举报