假设中国的国土总和是不变的。 每个国家都可以用他的国土面积代替, 又两种可能,一种是两个国家合并为1个,那么新国家的面积为两者之和。 一种是一个国家分裂为2个,那么2个新国家的面积之和为原国家的面积。 WJMZBMR现在知道了很遥远的过去中国的状态,又知道了中国现在的状态,想知道至少要几次操作(分裂和合并各算一次操作),能让中国从当时状态到达现在的状态。
题解:
首先,两个集合能通过分裂合并得到,那他们的和一定相等,而且如果两个集合中没有任何一个子集和是相等的,只能通过将第一个集合合并完之后分裂成第二个集合,步数为
n1+n2−2
,如果有子集的和相等,那么这就是个子问题,设最多可分成
k
个子集和,那么答案就为
不妨将第二个集合元素取负放入第一个集合,答案并不会影响。
对于一个集合,如果他的和不为0,那么肯定有一位数字是无用的,可以从更小的集合转移过来。
如果和为0,考虑依次删除每个元素(此时一定会枚举到一个最小的为0的集合,并且减去这个集合的贡献,也就是1),最后加上1就好了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
const int Maxn=(1<<20)+20;
int n1,n2,f[Maxn],sum[Maxn];
int main(){
scanf("%d",&n1);
for(int i=0;i<n1;i++)scanf("%d",&sum[(1<<i)]);
scanf("%d",&n2);
for(int i=0;i<n2;i++)scanf("%d",&sum[(1<<(n1+i))]),sum[(1<<(n1+i))]=-sum[(1<<(n1+i))];
static int lim=(1<<(n1+n2))-1;
for(int i=1;i<=lim;i++){
sum[i]=sum[(i&(-i))]+sum[i-(i&(-i))];
for(int j=0;(1ll<<j)<=i;++j){
if(i&(1ll<<j))f[i]=max(f[i],f[i^(1ll<<j)]);
}
f[i]+=(!sum[i]);
}
printf("%d\n",n1+n2-2*f[lim]);
}