整数划分

整数划分

一个正整数n可以表示成若干个正整数之和,形如:n=n1+n2+…+nk,其中n1≥n2≥…≥nk。
我们将这样的一种表示称为正整数n的一种划分。
现在给定一个正整数n,请你求出n共有多少种不同的划分方法。

输入格式

共一行,包含一个整数n。

输出格式

共一行,包含一个整数,表示总划分数量。
由于答案可能很大,输出结果请对1e9+7取模。

数据范围

1≤n≤1000

输入样例

5

输出样例

7

题目分析
方法一

因为输入一个数n,求n共有多少种不同的划分方法。首先因为是正整数的组合,因此我们可知,选择数的数量最多为n个1,因此选择数的数量不可能超过n

因此我们何以将其当做完全背包问题来看待,将n视为背包容量,其余数字本身的数值即为数值所占容量。

因此我们设 ij 两数
i表示选择的次数
j表示数值的大小

以下为状态转移方程的推导

f[i][j]= f[i-1][j]+f[i-1][j-i]+f[i-1][j-i* 2]+……+f[i-1][j-i*n]

f[i][j-i]= f[i-1][j-i]+f[i-1][j-i* 2]+f[i-1][j-i* 3]+……+f[i-1][j-i*n]
f[i][j]=f[i-1][j]+f[i][j-i]

因此代码如下

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010,M=1e9+7;
int dp[N],n;
int main()
{
    cin>>n;
    dp[0]=1;
    for(int i=1;i<=n;i++)
    for(int j=i;j<=n;j++)dp[j]=(dp[j]+dp[j-i])%M;
    cout<<dp[n];
    return 0;
}
方法二

所有总和为i,并且恰好表示成j个数的和的方案
可以将f[i][j]的方案数分为两种情况
1:方案中存在最小值为1的情况,这种请情况下我们去除1
则可得f[i-1][j-1].

2:方案中的最小值大于1,这时方案中的每个数均减去1
则此时i=i-j,同时由于每个数都大于1,因此方案数量不会变化
因此可得 f[i-j][j]

由于f[i][j]可将所有请情况分为上述两种情况,因此f[i][j]=f[i-1][j-1]+f[i-j][j]

因此f[i][j]=f[i-1][j-1]+f[i-j][j]为该题的状态转移方程。
由于i为总和,j为方案中数的个数
因此答案为(假设输入的数为n)
ans=f[n][1]+f[n][2]+……+f[n][n];

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010,M=1e9+7;
int dp[N][N],n,ans;
int main()
{
    cin>>n;
    dp[0][0]=1;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=i;j++)dp[i][j]=(dp[i-1][j-1]+dp[i-j][j])%M;
    for(int i=1;i<=n;i++)ans=(ans+dp[n][i])%M;
    cout<<ans;
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值