BZOJ 2064 分裂

Posted on 2016-10-30 17:54  ziliuziliu  阅读(143)  评论(0编辑  收藏  举报

哪里有什么不可言会的嘛。。。

考虑原本的操作数为n+m(将所有面积放到一个奇怪的地方去,从那个奇怪的地方取面积)。

然而有些子集的和是相等的,这样这些子集就并不用放到那个奇怪的地方去。也不用取出来。少2次操作。

dp[s]表示最多从这个集合里分出多少个子集,使得a,b对应子集和相等。(表示本来要dp[s][t]的。。。一个意思了。。。)

然后转移。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,sum[1<<21],f[1<<21];
int lowbit(int x)
{
    return (x&(-x));
}
int main()
{
    scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&sum[1<<i]);
    scanf("%d",&m);for (int i=1;i<=m;i++) {scanf("%d",&sum[1<<(n+i)]);sum[1<<(n+i)]=-sum[1<<(n+i)];}
    n+=m;
    int top=1<<n;
    for (int i=1;i<top;i++)
    {
        sum[i]=sum[lowbit(i)]+sum[i-lowbit(i)];
        for (int j=1;j<=n;j++)
        {
            if (i&(1<<j)) 
                f[i]=max(f[i],f[i-(1<<j)]);
        }
        f[i]+=(sum[i]==0);
    }
    printf("%d\n",n-2*f[top-1]);
    return 0;
}