51Nod - 1201 整数划分

将N分为若干个不同整数的和,有多少种不同的划分方式,例如:n = 6,{6} {1,5} {2,4} {1,2,3},共4种。由于数据较大,输出Mod 10^9 + 7的结果即可。
Input
输入1个数N(1 <= N <= 50000)。
Output
输出划分的数量Mod 10^9 + 7。
Sample Input
6
Sample Output
4

解题思路:http://www.cnblogs.com/HAdolf-HQY/p/6323034.html
这道题与CodeVS的“数的划分”十分类似,但那道题求的是:将n分成m份的方案数,并且每份是可以相同的;而这道题却要求所有划分方法的划分方案的总数,并且每份不能相同。满足这种要求的最大数也就是1+2+3+4+…+m<=n,而题目规定n<=50000,所以(1+m)*m/2<=50000,解得m<316,所以最多只能将n分成316份,这样便大大缩小了数组的大小范围。

有了m的范围,我们便可以定义一个F数组[0..50000,1..316],F[i][j]表示将数i分为j份的方案数总和。

于是便有了状态转移方程:f[i][j]:=f[i-j,j]+f[i-j,j-1]。

下面来具体解释一下这个方程:

1、f[i-j,j]表示的是将i分为不包含1(min>=2)的方案总个数,例如,6(=9-3)分成3份可以分为{1,2,3},则9可以分为{1+1,2+1,3+1}->{2,3,4}【仅1种

2、f[i-j,j-1]表示的是将i分为包含1(min=1)的方案总个数,例如,6=(=9-3)分成2(=3-1)可以分为{0,1,5}{0,2,4},则9可以分为{0+1,1+1,5+1}{0+1,2+1,4+1}->{1,2,6}{1,3,5}【共2种

至于为什么状态转移方程的f[i-j,j-1]与“数的划分”中的f[i-1,j-1]存在着区别,其根本原因是,一个可以分成相同的数,而另一个则不能。多减的这(j-1)其实是为了保证划分中的数据不存在重复并一定从小到大排列。

AC代码:

#include<stdio.h>
#include<math.h>

int a[50000][316];

int main()
{
    int n;
    long long sum=0;
    scanf("%d",&n);
    a[0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=316;j++)
            if(i>=j) a[i][j]=(a[i-j][j]+a[i-j][j-1])%1000000007;
    for(int i=1;i<sqrt(2*n);i++)
        sum=(sum+a[n][i])%1000000007;
    printf("%d\n",sum);
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值