整数划分
将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
题解:
状态转移方程: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}
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}
至于为什么状态转移方程的f[i-j,j-1]与“数的划分”中的f[i-1,j-1]存在着区别,其根本原因是,一个可以分成相同的数,而另一个则不能。多减的这(j-1)其实是为了保证划分中的数据不存在重复并一定从小到大排列。
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[50050][350];
int main()
{
int n;
while(~scanf("%d",&n))
{
int i,j,sum=0;
memset(dp,0,sizeof(dp));
dp[1][1]=1;
for (i=1;i<=n;i++)
for (j=1;j<min(350,i);j++)
dp[i][j]=(dp[i-j][j]+dp[i-j][j-1])%1000000007;
for (i=1;i<=350;i++)
sum=(sum+dp[n][i])%1000000007;
printf("%d\n",sum);
}
}