[AcWing 900] 整数划分

image

类比完全背包 复杂度 \(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;
}

  1. 状态表示
    \(f[i][j]\) 表示从数字 \(1\) ~ \(i\) 中选,且总和等于 \(j\) 的选法数量
  2. 状态转移
    类比完全背包的优化方式
    $ 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;
}

  1. 状态表示
    $ f[i][j] $ 表示总和是 $ i $ ,并且分成 $ j $ 个数的方案数量
  2. 状态转移
    \(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] $
  3. 结果
    要求的是总和为 \(n\) 的方案数量,可以分成 \(1, 2, 3, \cdots , n\) 个数,总的方案数是这些不同分法方案个数之和
posted @ 2022-05-24 20:44  wKingYu  阅读(42)  评论(0)    收藏  举报