
类比完全背包 复杂度 \(O(n^{2})\)
总体复杂度 \(1000^{2} = 1 \times 10^{6}\)
点击查看代码
#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;
}
- 状态表示
\(f[i][j]\) 表示从数字 \(1\) ~ \(i\) 中选,且总和等于 \(j\) 的选法数量
- 状态转移
类比完全背包的优化方式
$ f[i][j] = f[i - 1][j] + f[i - 1][j - i] + f[i - 1][j - 2i] + \cdots $ ,
$ f[i][j - i] = f[i - 1][j - i] + f[i - 1][j - 2i] + \cdots $ ,
可以得到 $ f[i][j] = f[i - 1][j] + f[i][j - i] $
另一种思考方式 复杂度同上
点击查看代码
#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 ++)
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;
}
- 状态表示
$ f[i][j] $ 表示总和是 $ i $ ,并且分成 $ j $ 个数的方案数量
- 状态转移
\(f[i][j]\) 分为两种情况:
① 分成的数中最小的数为 \(1\) ,可以把 \(1\) 单独拿出来,等价于 $ f[i - 1][j - 1] $
② 分成的数中最小的数大于 \(1\) ,可以把所有分成的数都减去 \(1\) ,总和减去 \(j\) ,等价于 \(f[i - j][j]\)
状态转移方程为:$ f[i][j] = f[i - 1][j - 1] + f[i - j][j] $
- 结果
要求的是总和为 \(n\) 的方案数量,可以分成 \(1, 2, 3, \cdots , n\) 个数,总的方案数是这些不同分法方案个数之和