1 条题解
-
2
如果没有每个盒子放不超过个的限制直接插板法求解。
考虑。
状态设计:定义为前个盒子放个球的方案数。
转移:考虑第个盒子放几个球即可,显然第个盒子可以放个取最小值是因为目前只考虑了个球。
初始化,前个盒子放个球,什么都不放也算一种方案
因此
此时是的转移会超时。
void solve() { cin >> n >> m >> p; for (int i = 0; i <= m; i++) dp[i][0] = 1; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { for (int k = 0; k <= min(j, p); k++) { dp[i][j] += dp[i - 1][j - k]; dp[i][j] %= mod; } } } cout << dp[m][n]; }
考虑如何加速转移,发现每次都是固定,多增加了,我们来研究一下相比于的变化。
可以发现首先后者比前者多了一项,并且前者一直减到了,后者只减到了
因此我们维护变化的两部分结果即可。
也就是求解新的加上之前的以及加上没有的部分,并且减去多加的部分
此时需要注意只有 才需要多加,因为的时候,大家最后一项都是没有区别。
完整代码。
void solve() { cin >> n >> m >> p; for (int i = 0; i <= m; i++) dp[i][0] = 1; for (int i = 1; i <= m; i++) { int sum = i;//sum记录上一次dp[i][j],初始化为i,其实是因为dp[i][1]的方案数,前i个盒子放1个球,自然是i种方案 for (int j = 1; j <= n; j++) { dp[i][j] = sum; sum = (sum + dp[i - 1][j + 1]) % mod; if (j - p >= 0) sum = (sum - dp[i - 1][j - p] + mod) % mod; } } cout << dp[m][n]; }
- 1
信息
- ID
- 357
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- 递交数
- 95
- 已通过
- 19
- 上传者