【USACO TRAINING】子集的和

来源:互联网 发布:阿里云网站客服 编辑:程序博客网 时间:2024/06/08 09:41

      • 题目描述
      • 输入
      • 输出
      • 样例输入
      • 样例输出
      • 分析
      • 代码

题目描述

    对于从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 LOCALlong 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;}
原创粉丝点击