BZOJ 2064: 分裂 状压动归

最多的操作次数是 $n+m-1$ (相当于把第一个暴力合并,再暴力拆成第二个).
如果第一个序列的一个子序列和第二个区间的子序列相等,那么总次数就可以减 $2$.
将第二个序列所有数取反,直接求解有多少个子序列的和为 $0$ 即可
$ans=n+m-dp[1<<(n+m)-1]$
具体:

  • $dp[i]=max(dp[i],dp[i xor (j<<1)])$
  • $dp[i]=dp[i]+1, sum[i]=0$
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=22;
int dp[1<<maxn],num[maxn],sum[1<<maxn];
int main()
{
    freopen("in.txt","r",stdin);
    int n,m,N;
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d",&num[i]);
    scanf("%d",&m);
    for(int i=n+1;i<=n+m;++i)
    {
        scanf("%d",&num[i]);
        num[i]=-num[i];
    }
    N=n+m;
    for(int i=1;i<(1<<N);++i)
    {
        sum[i]=0;
        for(int j=1;j<=N;++j)
        {
            if(i&(1<<(j-1)) )
            {
                sum[i]+=num[j];
                dp[i]=max(dp[i],dp[i^(1<<(j-1))]);
            }
        }
        if(sum[i]==0)++dp[i];
    }
    printf("%d",n+m-2*dp[(1<<N)-1]);
    return 0;
}

  

posted @ 2018-08-24 19:04  EM-LGH  阅读(149)  评论(0编辑  收藏  举报