蜗牛

一步一步往上爬

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

模板题 【整数划分】

两种划分方式

前i个数总和为j

总和为i的j个数

都有边界问题需要处理

一个正整数 n 可以表示成若干个正整数之和,形如:n=n1+n2+…+nk,其中 n1≥n2≥…≥nk,k≥1。

我们将这样的一种表示称为正整数 n 的一种划分。

现在给定一个正整数 n,请你求出 n 共有多少种不同的划分方法。

输入格式
共一行,包含一个整数 n。

输出格式
共一行,包含一个整数,表示总划分数量。

由于答案可能很大,输出结果请对 109+7 取模。

数据范围
1≤n≤1000
输入样例:
5
输出样例:
7

1转化为完全背包问题,求数量

容量为n,n个物品体积分别为1-n
f[i][j] = f[i-1][j] + f[i-1][j-i] + f[i-1][j-2*i] + ... +

1.1 f[i][j] = f[i-1][j]+f[i][j-i]

前i个物品容量为j的方案的集合

代码:
#include<bits/stdc++.h>

using namespace std;

const int N = 1010, M = 1e9+7;

int n;
int f[N][N];

int main()
{
	cin>>n;
	for( int i = 0; i <= n; i++ )
		f[i][0] = 1;//前i个物品都不选也是一种方案
	for( int i = 1; i <= n; i++ )
		for( int j = 1; j <= n; j++ ){
			f[i][j] = f[i-1][j]%M;
			if(j >= i)
				f[i][j] = (f[i-1][j]+f[i][j-i])%M;
		}
	cout<<f[n][n]<<endl;
	
	return 0;
}

1.2 优化到一维

f[j] = f[j]+f[j-i];

#include<bits/stdc++.h>

using namespace std;

const int N = 1010, M = 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])%M;
	cout<<f[n]<<endl;
	
	return 0;
}

计数类DP

f[i][j]表示所有总和为i,并且恰好表示成j个数的和的方案的集合
根据方案中最小值有没有1来进行集合划分,分为f[i-1[j-1]和f[i-j][j],
有一个边界问题,当总和为0时表示成0个数的方案也算一种
最后求和即可

#include<bits/stdc++.h>

using namespace std;

const int N =  1010, M = 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])%M;
	int res = 0;
	for( int i = 1; i <= n; i++ )
		res = (res+f[n][i])%M;
	cout<<res<<endl;
	
	return 0;
}
posted on 2021-10-05 15:04  对影丶成三人  阅读(64)  评论(0)    收藏  举报