bzoj 2679: [Usaco2012 Open]Balanced Cow Subsets 折半搜索

来源:互联网 发布:java编程思想 在线 编辑:程序博客网 时间:2024/06/06 13:11

题意

给出N(1≤N≤20)个数M(i) (1 <= M(i) <= 100,000,000),在其中选若干个数,如果这几个数可以分成两个和相等的集合,那么方案数加1。问总方案数。

分析

容易得知每个数的系数可以为-1,1,0,那么我们采用折半搜索,分别搜索出前后半段在每种状态下可能的和,然后排个序,用双指针统计答案即可。

程序跑的飞慢……

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define N 25using namespace std;int cnt1,cnt2,n,a[N],vis[1048605];struct data{int s,now;}c[60005],b[60005];void dfs(int x,int y,int s,int now){    if (x>y)    {        if (y==n/2)        {            b[++cnt1].s=s;b[cnt1].now=now;        }else        {            c[++cnt2].s=s;c[cnt2].now=now;        }        return;    }    dfs(x+1,y,s,now);    dfs(x+1,y,s-a[x],now+(1<<(x-1)));    dfs(x+1,y,s+a[x],now+(1<<(x-1)));}bool cmp1(data a,data b){    return a.s<b.s;}bool cmp2(data a,data b){    return a.s>b.s;}int main(){    //freopen("subset.in","r",stdin);    //freopen("subset.out","w",stdout);    scanf("%d",&n);    for (int i=1;i<=n;i++)        scanf("%d",&a[i]);    dfs(1,n/2,0,0);    dfs(n/2+1,n,0,0);    sort(b+1,b+cnt1+1,cmp1);    sort(c+1,c+cnt2+1,cmp2);    int i=1,j=1,ans=0;    while (i<=cnt1&&j<=cnt2)    {        while (c[j].s>-b[i].s&&j<=cnt2) j++;        int k=j;        while (j<=cnt2&&c[j].s==-b[i].s)        {            if (!vis[b[i].now|c[j].now])            {                vis[b[i].now|c[j].now]=1;                ans++;            }            j++;        }        if (b[i].s==b[i+1].s&&i<cnt1) j=k;        i++;    }    printf("%d",ans-1);    return 0;}
0 0