整数划分
题目大意
一个正整数 n n n 可以表示成若干个正整数之和,形如: n = n 1 + n 2 + … + n k n=n_1+n_2+…+n_k n=n1+n2+…+nk,其中 n 1 ≥ n 2 ≥ … ≥ n k , k ≥ 1 n_1≥n_2≥…≥n_k,k≥1 n1≥n2≥…≥nk,k≥1。
我们将这样的一种表示称为正整数n的一种划分。
现在给定一个正整数 n n n,请你求出 n n n 共有多少种不同的划分方法。
输入格式
共一行,包含一个整数 n n n。
输出格式
共一行,包含一个整数,表示总划分数量。
由于答案可能很大,输出结果请对 1 0 9 + 7 10^9+7 109+7取模。
数据范围: 1 ≤ n ≤ 1000 1≤n≤1000 1≤n≤1000
输入样例
5
输出样例
7
1. 状 态 表 示 : d p [ i ] [ j ] 表 示 j 个 数 凑 出 容 量 为 i 的 方 案 数 。 1.状态表示:dp[i][j]表示j个数凑出容量为i的方案数。 1.状态表示:dp[i][j]表示j个数凑出容量为i的方案数。
2. 状 态 转 移 方 程 : 最 后 一 个 数 是 大 于 0 与 最 后 一 个 数 大 于 0 的 两 种 方 案 数 之 和 。 即 d p [ i ] [ j ] = d p [ i ] [ j − 1 ] + d p [ i − j ] [ j ] 2.状态转移方程:最后一个数是大于 0 与最后一个数大于 0 的两种方案数之和。即 dp[i][j] = dp[i][j-1] + dp[i-j][j] 2.状态转移方程:最后一个数是大于0与最后一个数大于0的两种方案数之和。即dp[i][j]=dp[i][j−1]+dp[i−j][j]
#include <cstdio>
using namespace std;
const int mod=1e9+7;
int dp[1007][1007]; // dp[i][j]:前 j 个数,容量为 i 的方案数
int main()
{
int n;
scanf("%d",&n);
for(int i = 0; i <= n; i++) dp[0][i] = 1; // i 个数,全 0 方案数为 1
for(int i = 0; i <= n; i++) //容量为 i
for(int j = 1; j <= n; j++) // 个数为 j 个
{
dp[i][j] = dp[i][j-1]%mod;
if(i >= j) dp[i][j] += dp[i-j][j]%mod;
}
printf("%d\n",dp[n][n]);
return 0;
}
#include <cstdio>
using namespace std;
const int mod=1e9+7;
int dp[1007];
int main()
{
int n;
scanf("%d",&n);
dp[0]=1; //容量为 0 的方案数是 1
for(int i=1;i<=n;++i) //枚举物品
for(int j=i;j<=n;++j) //枚举容量
dp[j]=(dp[j]+dp[j-i])%mod;
printf("%d\n",dp[n]);
return 0;
}
鸣人的影分身
题目大意
在火影忍者的世界里,令敌人捉摸不透是非常关键的。
我们的主角漩涡鸣人所拥有的一个招数——多重影分身之术——就是一个很好的例子。
影分身是由鸣人身体的查克拉能量制造的,使用的查克拉越多,制造出的影分身越强。
针对不同的作战情况,鸣人可以选择制造出各种强度的影分身,有的用来佯攻,有的用来发起致命一击。
那么问题来了,假设鸣人的查克拉能量为 M M M,他影分身的个数最多为 N N N,那么制造影分身时有多少种不同的分配方法?
注意:影分身可以分配0点能量。
分配方案不考虑顺序,例如: M = 7 , N = 3 M=7,N=3 M=7,N=3,那么 (2,2,3) 和 (2,3,2) 被视为同一种方案。
输入格式
第一行是测试数据的数目 t t t。
以下每行均包含二个整数 M M M 和 N N N,以空格分开。
输出格式
对输入的每组数据 M M M 和 N N N,用一行输出分配的方法数。
数据范围: 0 ≤ t ≤ 20 , 1 ≤ M , N ≤ 10 0≤t≤20,1≤M,N≤10 0≤t≤20,1≤M,N≤10
输入样例
1
7 3
输出样例
8
1.确定状态: d p [ i ] [ j ] dp[i][j] dp[i][j] 表示 j j j 个数,和为 i i i 的方案数。
2.状态转移方程:最后一位是 0 表示为 d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j−1],最后一位大于 0 表示为 d p [ i − j ] [ j ] dp[i-j][j] dp[i−j][j]
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 20;
int dp[maxn][maxn];
int main()
{
int n, m, t;
scanf("%d",&t);
while(t--)
{
memset(dp, 0, sizeof dp);
scanf("%d%d",&m,&n);
dp[0][0] = 1;
for(int i = 0; i <= m; i++)
for(int j = 1; j <= n; j++)
{
dp[i][j] = dp[i][j-1]; //最后一个数是 0
if(i >= j) dp[i][j] += dp[i-j][j]; // 最后一个数大于 0
}
printf("%d\n",dp[m][n]);
}
return 0;
}
糖果
题目大意
由于在维护世界和平的事务中做出巨大贡献, D z x Dzx Dzx 被赠予糖果公司2010年5月23日当天无限量糖果免费优惠券。
在这一天, D z x Dzx Dzx 可以从糖果公司的 N N N 件产品中任意选择若干件带回家享用。
糖果公司的 N N N 件产品每件都包含数量不同的糖果。
D z x Dzx Dzx 希望他选择的产品包含的糖果总数是 K K K 的整数倍,这样他才能平均地将糖果分给帮助他维护世界和平的伙伴们。
当然,在满足这一条件的基础上,糖果总数越多越好。
D z x Dzx Dzx 最多能带走多少糖果呢?
注意: D z x Dzx Dzx只能将糖果公司的产品整件带走。
输入格式
第一行包含两个整数 N N N 和 K K K。
以下 N N N 行每行 1 个整数,表示糖果公司该件产品中包含的糖果数目,不超过 1000000。
输出格式
符合要求的最多能达到的糖果总数,如果不能达到 K K K 的倍数这一要求,输出 0。
数据范围: 1 ≤ N ≤ 100 , 1 ≤ K ≤ 100 1≤N≤100,1≤K≤100 1≤N≤100,1≤K≤100
输入样例
5 7
1
2
3
4
5
输出样例
14
样例解释: D z x Dzx