bzoj 2064: 分裂【状态压缩】

来源:互联网 发布:听歌不要钱的软件 编辑:程序博客网 时间:2024/06/05 03:56

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2064

题意:将n个数以最少操作变成m个数,操作为合并分解。

分析:前后数的总和不变,我们可以将n个数合并成一个数,然后分解成m个数,操作数是n+m-2,但是有些数是不用合并的,枚举n和m的子集,每有一对相等ans-2.

这时我们取n的为正数,m的为负数。

代码:

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<string>#include<vector>#include<queue>#include<cmath>#include<stack>#include<set>#include<map>#define INF 0x3f3f3f3f#define Mn 1<<20#define Mm 2010#define mod 1000000007#define CLR(a,b) memset((a),(b),sizeof((a)))#define CPY(a,b) memcpy ((a), (b), sizeof((a)))#pragma comment(linker, "/STACK:102400000,102400000")#define ul u<<1#define ur (u<<1)|1using namespace std;typedef long long ll;int dp[Mn];int a[30],b[30];int sum[Mn];int lowbit(int x) {    return x&(-x);}int main() {    int n,m,x;    scanf("%d",&n);    int num=0;    for(int i=0;i<n;i++) {        scanf("%d",&sum[1<<i]);    }    scanf("%d",&m);    for(int i=0;i<m;i++) {        scanf("%d",&x);        sum[1<<(i+n)]=-x;    }    n+=m;    int all=(1<<n)-1;    for(int s=1;s<=all;s++) {        int x=lowbit(s);        sum[s]=sum[x]+sum[s^x];        for(int j=0;j<n;j++)            if(s&(1<<j)) dp[s]=max(dp[s],dp[s^(1<<j)]);        if(!sum[s]) dp[s]++;    }    cout<<n-2*dp[all]<<endl;    return 0;}


0 0