EOJ 1009 整数的拆分 生成函数法

题目描述

将正整数 n 表示成一系列正整数之和 : n=n1+n2+…+nk,其中 n1≥n2≥…≥nk≥1(k≥1)

正整数 n 的这种表示称为正整数 n 的拆分。求正整数 n 的不同拆分个数。

例如,正整数 6 有如下 11 种不同的拆分 :

6;

5+1;

4+2,4+1+1;

3+3,3+2+1,3+1+1+1;

2+2+2,2+2+1+1,2+1+1+1+1;

1+1+1+1+1+1。

例如,正整数 3 有如下 3 种不同的拆分 :

3;

2+1;

1+1+1。

输入格式

本题有多组测试数据,每组一行,每行有一个正整数 N(1<=N<=100)

输出格式

每组测试数据输出一行,表示有多少种拆分方法

样例

input

1
3
5

output

1
3
7

思路:

根据百度百科上整数分拆的解释,选取了生成函数的方法进行实现,速度较快,代码实现也简单。一个数n可以拆分为若干个1,若干个2,若干个3...若干个n的组合,限制要求是组合之和等于n,由此可得,1最多有n个,2最多有n/2个,以此类推。利用指数函数相乘可以看做指数的相加这一性质,设计生成函数(1+x+x^2+x^3+...+x^n)(1+x^2+x^4+...+x^n)(1+x^3+x^6+x^9+...+x^n)...(1+x^n),对于这个函数的解释,可以理解为,第一个括号表示因子1的可能组合,即0个1一直到n个1,第二个括号表示0个2、1个2(x^2)、2个2(x^(2+2)=x^4)、3个2(x^(2+2+2)=x^6)等等组合,每个因子可能的组合相乘,得到的x的指数即为一组组合的和,其系数表示组合的个数。取指数为n的系数(即x^n的系数)为最终答案,代码实现如下:

#include <iostream>
#include <cstring>
#define MAXN 102

using namespace std;

int main()
{
    int n;
    while(cin>>n){//构造(1+x+x^2+x^3+..+x^n)(1+x^2+x^4+x^6+..+x^n)(1+x^3+x^6+..+x^n)..(1+x^n),最终结果中x^n前的系数就是分拆数结果
        long long c1[MAXN] = {0};
        long long c2[MAXN] = {0}; //用来记录多项式乘法的中间结果
        for(int i=0; i<MAXN; ++i)//初始化c1为第一个括号中的多项式,系数都为1
            c1[i] = 1;
        for(int i=2; i<=n; ++i){//循环n个括号
            for(int j=0; j<=n; ++j)//累计的多项式乘积的每一项
                for(int k=0; j+k<=n; k+=i){ //下一个括号里的每一项,大于n次的x幂都不用考虑
                    c2[j+k] += c1[j]; //实质上为c2[j+k]+=c[j]*1,因为所有项的系数都为1
                }
            memcpy(c1, c2, MAXN*sizeof(long long));
            memset(c2, 0, MAXN*sizeof(long long));
        }
        cout<<c1[n]<<endl;
    }
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值