子集的和

题目描述

对于从1到N (1 <= N <= 39) 的连续整数集合,能划分成两个子集合,且保证每个集合的数字之和是相等的。
举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,他们每个的所有数字和是相等的:
{3} and {1,2}
这是唯一一种分法(交换集合位置被认为是同一种划分方案,因此不会增加划分方案总数)
如果N=7,有四种方法能划分集合{1,2,3,4,5,6,7},每一种分发的子集合各数字和是相等的:
{1,6,7} 和 {2,3,4,5} 1+6+7=2+3+4+5
{2,5,7} 和 {1,3,4,6}
{3,4,7} 和 {1,2,5,6}
{1,2,4,7} 和 {3,5,6}
给出N,你的程序应该输出划分方案总数,如果不存在这样的划分方案,则输出0。

输入

第1行:一个整数N

输出

第1行:输出划分方案总数,如果不存在则输出0。

样例输入

7

样例输出

4

分析

首先我们应该意识到:假如(1+n)*n/2是一个奇数,那么他肯定不能被划分为两个整数,也就应该输出“0”。同时,由于划分方案数会是正常答案的两倍,所以应该在输出时把方案数除以2。

代码

#include<bits/stdc++.h>
using namespace std;
//#define LOCAL
long long f[405]={1};
int main()
{
    #ifdef LOCAL
        freopen("data.in","r",stdin);//文件重定向
        freopen("data.out","w",stdout);//文件重定向
    #endif
    ios::sync_with_stdio(false);
    int n;
    cin>>n;
    int sum=(n+1)*n/2;//求和公式
    if(sum%2!=0)//如果和为奇数
    {
        cout<<0<<endl;
        return 0;
    }
    sum/=2;//其中一个子集的和
    for(int i=1;i<=n;i++)
    {
        for(int j=sum;j>=i;j--)
            f[j]=f[j]+f[j-i];//状态转移方程式:f[j]+=f[j-i]
    }
    cout<<f[sum]/2<<endl;//输出时除以2
    return 0;
}
posted @ 2017-08-25 17:12  SteinGate  阅读(210)  评论(0编辑  收藏  举报