1365. 子集的和

解法一:01背包

\(1 \sim n\)的总和\(sum=\frac{n(n+1)}{2}\),若将整数集合\(1 \sim n\)划分成两个和相等的子集,则子集的和\(sum'=\frac{n(n+1)}{4}\)

问题转化为\(1 \sim n\)中选出若干个数,总和为\(sum'\)的方案数。

const int N = 400;
LL f[N];
int n;

int main()
{
    cin>>n;
    
    int sum=n*(n+1)/2;
    if(sum % 2) puts("0");
    else
    {
        sum /= 2;
        f[0]=1;
        for(int i=1;i<=n;i++)
            for(int j=sum;j>=i;j--)
                f[j]+=f[j-i];
        cout<<f[sum]/2<<endl;
    }
    
    //system("pause");
    return 0;
}

解法二:折半搜索

\(fl[i]\)\(fr[i]\)分别表示前\(\frac{n}{2}\)个数能凑出的和为\(i\)的个数、后\(\frac{n}{2}\)个数能凑出的和为\(i\)的个数和。

const int N=600;
int fl[N],fr[N];
int n;

void dfs(int l,int r,int sum,int *f)
{
    if(l > r)
    {
        f[sum]++;
        return;
    }
    dfs(l+1,r,sum+l,f);
    dfs(l+1,r,sum,f);
}

int main()
{
    cin>>n;

    int sum=n*(n+1)/2;
    if(sum & 1) puts("0");
    else
    {
        sum /= 2;
        dfs(1,n/2,0,fl);
        dfs(n/2+1,n,0,fr);

        LL ans=0;
        for(int i=0;i<=sum;i++)
            ans+=fl[i]*fr[sum-i];
        cout<<ans/2<<endl;
    }

    //system("pause");
    return 0;
}

posted @ 2021-06-02 16:17  Dazzling!  阅读(121)  评论(0编辑  收藏  举报