算法学习笔记(46)——计数类DP
计数类 DP
问题描述
一个正整数 可以表示成若干个正整数之和,形如:,其中 。
我们将这样的一种表示称为正整数 的一种划分。
现在给定一个正整数 ,请你求出 共有多少种不同的划分方法。
输入格式
共一行,包含一个整数 。
输出格式
共一行,包含一个整数,表示总划分数量。
由于答案可能很大,输出结果请对 取模。
数据范围
输入样例:
5
输出样例:
7
算法1(完全背包)
可将本题完全背包问题,容量是 的背包,共有 件物品,每件物品的体积分别是 ,每种物品有无限个,求恰好装满背包的方案数。
状态表示
表示从第 件物品中选,恰好装满 体积的方案数。
阶段划分
最后一件物品的个数。
- 选 件第 个物品,
- 选 件第 个物品,
- 选 件第 个物品,
- ......(以此类推)
- 选 件第 个物品,
转移方程
利用完全背包的优化思路,将第二个方程代入第一个方程,得到:
边界
容量为0时,前 i 个物品全不选也是一种方案
目标
#include <iostream>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int n;
int f[N][N];
int main()
{
cin >> n;
// 容量为0时,前 i 个物品全不选也是一种方案
for (int i = 0; i <= n; i ++ ) f[i][0] = 1;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ ) {
f[i][j] = f[i - 1][j] % mod;
if (j >= i) f[i][j] = (f[i - 1][j] + f[i][j - i]) % mod;
}
cout << f[n][n] << endl;
return 0;
}
维数优化:
#include <iostream>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int n;
int f[N];
int main()
{
cin >> n;
f[0] = 1;
for (int i = 1; i <= n; i ++ )
for (int j = i; j <= n; j ++ )
f[j] = (f[j] + f[j - i]) % mod;
cout << f[n] << endl;
return 0;
}
算法2
方案中最小值是 时的方案数,与去掉一个 的方案数 相同。
方案中最小值大于 时的方案数,与对每一个数减 (共有 个数,所以总和减 )的方案数 相同。
转移方程
边界
目标
#include <iostream>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int n;
int f[N][N];
int main()
{
cin >> n;
f[0][0] = 1;
for (int i = 1; i <= n; i ++ )
// 总和是i得数最多表示成i个数的和(均为1)
for (int j = 1; j <= i; j ++ )
f[i][j] = (f[i - 1][j - 1] + f[i - j][j]) % mod;
int res = 0;
for (int i = 1; i <= n; i ++ ) res = (res + f[n][i]) % mod;
cout << res << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】