牛客网-放苹果【划分数问题详解】

这道题是一个模板题,所以先上原模板:
在这里插入图片描述
这样的划分被称作 n n n m m m划分数,特别地, m = n m=n m=n时称作 n n n 的划分数、DP不仅对于求解最优问题有效,对于各种排列组合的个数、概率或者期望之类的计算同样很有用。在此,我们定义如下。

d p [ i ] [ j ] : j 的 i 划 分 总 数 dp[i][j]:j的i划分总数 dp[i][j]:ji

根据这一定义可以得到怎样的递推关系呢?将 j j j个划分成 i i i个的话,可以先取出 k k k个然后将剩下的 j − k j-k jk个分成 i − 1 i-1 i1份,这时大家是不是认为也许就可以得到下面的递推式了?
d p [ i ] [ j ] = ∑ k = 0 j d p [ i − 1 ] [ j − k ] dp[i][j]=\sum_{k=0}^j{dp[i-1][j-k]} dp[i][j]=k=0jdp[i1][jk]

但很不幸的是,这个递推是不正确的。用这个办法的话,例如1+1+2和1+2+1的划分就被当成是不同的划分来计数了。为了不重复计数,我们需要寻找别的递推关系。考虑 n n n m m m划分 { a 1 , a 2 , . . . , a m } \{a_1,a_2,...,a_m\} {a1,a2,...,am}

  • 如果有任意 a i > 0 a_i>0 ai>0,那么 { a 1 − 1 , a 2 − 1 , . . . , a m − 1 } \{a_1-1,a_2-1,...,a_m-1\} {a11,a21,...,am1}也就是 n − m n-m nm m m m划分此时这两个组合数是一样的,因为前者也只是给后者每个位置+1而已。
  • 如果存在 a i = 0 a_i=0 ai=0,那么就对应了 n n n m − 1 m-1 m1划分。

而对于 j > = i j>=i j>=i d p [ i ] [ j ] dp[i][j] dp[i][j]而言,这两种可能性显然都可以在他的排列种发生,而如果 j < i j<i j<i,那么只有第二种情况会发生。因此我们有

if(j>=i)dp[i][j]=(dp[i-1][j]+dp[i][j-i])\%M

else ~dp[i][j]=dp[i-1][j]

例题:牛客网-放苹果

题目描述

把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。

输入描述:

每行均包含二个整数M和N,以空格分开。1<=M,N<=10。

输出描述:

对输入的每组数据M和N,用一行输出相应的K。

#define ll int
#define vec vector<ll>
#define MAX 15
#define inf 0x3fffffff

ll dp[MAX][MAX];

int main() {
	ll M, N;
	while (cin >> M >> N) {
		memset(dp, 0, sizeof(dp));
		dp[0][0] = 1;
		for (int i = 1; i <= N; i++) {
			//j从零开始,也就是每行的第一列都是1 dp[i][0]=1 因为盘子可以为空
			for (int j = 0; j <= M; j++) {
				if (j >= i)dp[i][j] = dp[i - 1][j] + dp[i][j - i];
				else dp[i][j] = dp[i - 1][j];
			}
		}
		cout << dp[N][M] << endl;
	}
}
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值