Problem Description
"Well, it seems the first problem is too easy. I will let you know how foolish you are later." feng5166 says.
"The second problem is, given an positive integer N, we define an equation like this:
  N=a[1]+a[2]+a[3]+...+a[m];
  a[i]>0,1<=m<=N;
My question is how many different equations you can find for a given N.
For example, assume N is 4, we can find:
  4 = 4;
  4 = 3 + 1;
  4 = 2 + 2;
  4 = 2 + 1 + 1;
  4 = 1 + 1 + 1 + 1;
so the result is 5 when N is 4. Note that "4 = 3 + 1" and "4 = 1 + 3" is the same in this problem. Now, you do it!"
Input
The input contains several test cases. Each test case contains a positive integer N(1<=N<=120) which is mentioned above. The input is terminated by the end of file.
Output
For each test case, you have to output a line contains an integer P which indicate the different equations you have found.
Sample Input
4
10
20
Sample Output
5
42
627
解题思路:这题既可以用动态规划,也可以用母函数。
DP原先是递归而来的,这里就直接讲递推吧!
(整数划分有很多种,这里属于划分的多个整数可以相同)
首先定义dp[i][j]记录将整数i划分成所有元素都不大于j的所有情况数,下面举个栗子:
当i=4,j=1时,要求划分得到的所有元素都不大于j,所以划分法只有1种:{1,1,1,1};
当i=4,j=2时,。。。。。。。。。。。。。。。。。。。。。只有2种:{1,1,1,1},{2,1,1},{2,2};
当i=4,j=3时,。。。。。。。。。。。。。。。。。。。。。只有3种:{1,1,1,1},{2,1,1},{2,2},{3,1};
当i=4,j=4时,。。。。。。。。。。。。。。。。。。。。。只有4种:{1,1,1,1},{2,1,1},{2,2},{3,1},{4};
当i=4,j=5,6.....n(n为自然数)时,。。。。。。。。。。只有4种:{1,1,1,1},{2,1,1},{2,2},{3,1},{4};
从以上规律可以推出结论:当i==1||j==1,只有一种划分法;
一、当i<j时,由于分法不可能出现负数,所以dp[i][j]=dp[i][i];
二、当i==j时,分两种情况:①如果要划分出j这一个数,那么情况只有1种:{j};②如果不分,那么就将i分成所有元素不大于j-1的若干份,dp[i][j]=dp[i][j-1]。所以总的情况数为dp[i][j]=dp[i][j-1]+1;
三、当i>j时,也分两种情况:①如果要划分出j这一个数,注意此时的j<i,说明其剩下的整数(i-j)划分成的所有元素都在这个集合{j,a1,a2...}里,那么此时的dp[i][j]为把剩下的(i-j)这个整数划分成所有元素都不大于j时的情况数,即dp[i][j]=dp[i-j][j];②如果不分,那么就将i分成所有元素不大于j-1的若干份,dp[i][j]=dp[i][j-1]。所以总的情况数为dp[i][j]=dp[i-j][j]+dp[i][j-1]。
AC代码一之计数DP:
 #include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = ;
LL dp[maxn][maxn];int n;//dp[i][j]记录将整数i划分成所有元素不大于j的所有情况数
int main()
{//打表
for(int i=;i<maxn;i++)//将整数i划分成所有元素不大于1的分法和将整数1划分成所有元素不大于i(其实只有1本身)的分法都为1种
dp[i][]=dp[][i]=;
for(int i=;i<maxn;i++){//从划分2份开始
for(int j=;j<maxn;j++){//从整数2开始划分
if(i<j)dp[i][j]=dp[i][i];
else if(i==j)dp[i][j]=dp[i][j-]+;
else dp[i][j]=dp[i][j-]+dp[i-j][j];
}
}
while(cin>>n){
cout<<dp[n][n]<<endl;//最后输出总的情况数,即将整数n划分成不大于n的所有情况数
}
return ;
}

AC代码二:关于这种解法可以看看这篇博文:题解报告:hdu 1284 钱币兑换问题(简单数学orDP)

 #include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int main(){
LL n,dp[]={};//预处理打表
for(int i=;i<;++i)
for(int j=i;j<;++j)//每种数字可以看作无限个--->完全背包
dp[j]+=dp[j-i];
while(cin>>n){cout<<dp[n]<<endl;}
return ;
}

母函数解法,先贴一篇入门博文:母函数简介,看完后再看一篇:母函数的应用。普通型母函数其实就是把复杂的分类和分步求和过程具体为一个可以求解的"函数":通过将简单的构造(生成)函数展开多项式后可以发现一个规律:指数代表和数,每一项的系数代表凑成那一项指数的方案总数,实际上这就是多重集组合问题的求解答案。每个多项式中每一项前面的系数都为1,表示每种情况都有1种出现的可能。因此,我们只需构造出正确的生成函数,编程时通过模拟多个多项式相乘即可。对于此题构造出的生成函数就是G(x)=(1+x^1+x^2..+x^n)(1+x^2+x^4+x^6+...)(1+x^3+x^6+...)(...)(1+x^n),从这个"函数"中可以看出每一个多项式中有着完全背包的思想,即不取或取一件或取多件。注意:由于要求的是凑成和为n的方案数,所以多项式中每一项相乘得到的指数应不超过n,最终x^n前面的系数就是整数n的划分总方案数。

AC代码三:时间复杂度为O(n3)。

 #include<bits/stdc++.h>
using namespace std;
const int maxn=;
int n,c1[maxn],c2[maxn];
int main(){
while(~scanf("%d",&n)){
memset(c1,,sizeof(c1));//c1[ ]保存当前得到的多项式各项系数,c2[ ]保存每次计算时的各项系数的临时结果,并且每计算完一个多项式之后把c2[ ]拷贝给c1[ ],同时把c2[ ]清零
memset(c2,,sizeof(c2));
c1[]=;//指数为0的系数为1
for(int i=;i<=n;++i){//n个多项式
for(int j=;j<=n;++j)//指数最大不超过n,0~n
for(int k=;k+j<=n;k+=i)//当前第i个多项式的指数步长为i。现将多项式中指数为0~n的每一项去乘以当前第i项多项式中的每一项,得到的指数为j+k,由于第i个多项式中每一项前面的系数都为1,因此得到指数为j+k的系数为在原来的基础上加上指数为j的系数C1[j]即可
c2[j+k]+=c1[j];
for(int j=;j<=n;++j) //把c2[j]即指数为j(j∈[0,n])的每一项系数赋给c1[j],并且把c2[ ]清零
c1[j]=c2[j],c2[j]=;
}
printf("%d\n",c1[n]);//x^n的系数就是整数n的划分方案数。
}
return ;
}

题解报告:hdu 1028 Ignatius and the Princess III(母函数or计数DP)的更多相关文章

  1. hdu 1028 Ignatius and the Princess III 母函数

    Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  2. HDU 1028 Ignatius and the Princess III (递归,dp)

    以下引用部分全都来自:http://blog.csdn.net/ice_crazy/article/details/7478802  Ice—Crazy的专栏 分析: HDU 1028 摘: 本题的意 ...

  3. hdu 1028 Ignatius and the Princess III 简单dp

    题目链接:hdu 1028 Ignatius and the Princess III 题意:对于给定的n,问有多少种组成方式 思路:dp[i][j],i表示要求的数,j表示组成i的最大值,最后答案是 ...

  4. HDU 1028 Ignatius and the Princess III 整数的划分问题(打表或者记忆化搜索)

    传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1028 Ignatius and the Princess III Time Limit: 2000/1 ...

  5. hdu 1028 Ignatius and the Princess III(DP)

    Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  6. HDU 1028 Ignatius and the Princess III (母函数或者dp,找规律,)

    Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  7. hdu 1028 Ignatius and the Princess III (n的划分)

    Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  8. HDU 1028 Ignatius and the Princess III (生成函数/母函数)

    题目链接:HDU 1028 Problem Description "Well, it seems the first problem is too easy. I will let you ...

  9. HDU 1028 Ignatius and the Princess III (动态规划)

    题目链接:HDU 1028 Problem Description "Well, it seems the first problem is too easy. I will let you ...

随机推荐

  1. pyhthon第一个小脚本——文件备份

    先说说这个脚本的作用:对指定路径的文件进行压缩备份到另一个指定的路径,并且压缩文件的文件名用当时的日期+时间命名. 先是对着<简明Python教程>上的代码敲的,一堆错误,书上给的是lin ...

  2. python——正则表达式的理解

    概念:又称规则表达式,常用来检索.替换符合某个规则的文本. 理解:特殊字符--------->规则---------->过滤字符串 目的:1.匹配给定的字符串,2.从字符串中过滤出我们需要 ...

  3. 工资(money)

    (money/money.in/money.out) 时限1000ms 内存256MB 聪哥在暑假参加了打零工的活动,这个活动分为n个工作日,每个工作日的工资为Vi.有m个结算工钱的时间,聪哥可以自由 ...

  4. A multiprocessing system including an apparatus for optimizing spin-lock operations

    A multiprocessing system having a plurality of processing nodes interconnected by an interconnect ne ...

  5. Eddy's mistakes

    Problem Description Eddy usually writes  articles ,but he likes mixing the English letter uses, for ...

  6. 22、Java并发性和多线程-Java中的读/写锁

    以下内容转自http://ifeve.com/read-write-locks/: 相比Java中的锁(Locks in Java)里Lock实现,读写锁更复杂一些.假设你的程序中涉及到对一些共享资源 ...

  7. Mysql Innodb存储引擎 insert 死锁分析

    http://chenzhenianqing.cn/articles/1308.html

  8. Quartz.Net 使用心得(二)

    工作中需要做一个简易的Cron字符串生成器,并且要获取生成的Cron后面10次的触发时间来验证. 此问题困扰了我很久时间,CSDN上有一个Java版本的,本人菜鸟,想移植到C#中,语法上怎么也不通过. ...

  9. da,da_driver

    daSet=session.query(da).all() for da in daSet: da.mount_list=map(lambda x:x.mount_point , x for x in ...

  10. 用两种方法(递归和DP)实现了青蛙跳台阶

    做了这道题目: https://www.nowcoder.net/practice/8c82a5b80378478f9484d87d1c5f12a4?tpId=13&tqId=11161&am ...