[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;
}
我是咸鱼。转载博客请征得博主同意Orz