题目90:整数划分

来源:互联网 发布:vb对皮肤瘙痒有用吗 编辑:程序博客网 时间:2024/06/05 23:47

题目链接:

http://acm.nyist.net/JudgeOnline/problem.php?pid=90

描述

将正整数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。

输入

第一行是测试数据的数目M(1<=M<=10)。以下每行均包含一个整数n(1<=n<=10)。

输出

输出每组测试数据有多少种分法。

样例输入

1
6

样例输出

11

算法思想:

生成函数解法(组合数学中应用的母函数)。
先简单说明一下生成函数吧,下面是一个生成函数,
这里写图片描述
xk的系数ak代表了可获得数字k的组合数。
那么回到我们的问题中,我们怎么用生成函数去解决呢?

类似的,我们可以计算生成函数:
这里写图片描述
我们来做一个说明,第i个括号(1+xi+x2i+x3i · · ·)选择的元素代表了数字i在我们最终的划分中出现的次数,具体而言,如果我们在第i个括号中选择了元素 xc(i) * i 则表示数字 i 在我们最终的划分中出现了c(i)次。如果我们把最终从每个括号里面选择出来的元素相乘 x1 * c(1) · x2 * c(2) · x3 * c(3) · · · = x c(1) + 2 * c(2) + 3 * c(3)···.那么,xn的系数就是我们可以获得多少种不同的方式使得c(1) + 2 * c(2) + 3 * c(3)··· = n,也就是n的划分数(其中,c(i)代表了在一次划分中数字 i 的出现次数)。比如说25=6+4+4+3+2+2+2+1+1,用上式表示就是25=1(2)+2(3)+3(1)+4(2)+5(0)+6(1),也就是在划分中有两个1,三个2,一个3,两个4,0个5以及一个6。
假设x<1,那么我们可以将上面的生成函数表示为:
这里写图片描述
考虑到我们能选择的最大的数 i 是 m ,所以真正计算的时候我们需要对上面的生成函数式子做一下修改:

G(x) = (1+x+x^2+x^3+…+x^n) (1+x^2+x^4+…) (1+x^3+x^6+…) … (1+x^m)
= g(x,1) g(x,2) g(x,3) … g(x, n)

源代码

/*Author:杨林峰Date:2017.11.28NYOJ(90):整数划分*/#include <iostream> #include <cstring>using namespace std;#define N 11 unsigned long a[N];/*多项式a的系数数组*/ unsigned long b[N];/*多项式b的系数数组*/ unsigned long c[N];/*存储多项式a*b的结果*/  /*两个多项式进行乘法,系数分别在a和b中,结果保存到c ,项最大次数到N */  /*注意这里我们只需要计算到前N项就够了。*/ void Poly() {    int i, j;    memset(c, 0, sizeof(c));    for (i = 0; i<N; i++)    for (j = 0; j<N - i; j++) /*y<N-i: 确保i+j不会越界*/    c[i + j] += a[i] * b[j]; }  /*计算出前N项系数!即g(x,1) g(x,2)... g(x,n)的展开结果*/ void Init() {      int i, k;      memset(a, 0, sizeof(a));      memset(c, 0, sizeof(c));     for (i = 0; i<N; i++) a[i] = 1; /*第一个多项式:g(x, 1) = x^0 + x^1 + x^2 + x^3 +  */     for (k = 2; k<N; k++)     {        memset(b, 0, sizeof(b));        for (i = 0; i<N; i += k) b[i] = 1;/*第k个多项式:g(x, k) = x^0 + x^(k) + x^(2k) + x^(3k) +  */        Poly(); /* 多项式乘法:c= a*b */        memcpy(a, c, sizeof(c)); /*把相乘的结果从c复制到a中:c=a; */    }  } int main() {     int M, n;     cin >> M;     while (M--)     {         cin >> n;         Init();         cout << c[n] << endl;     }     return 0; }        
原创粉丝点击