1 条题解
-
1
【2022年省赛B组】试题I: 李白打酒加强版
题解
由于的最大值为100,要满足题目要求——在最后一次将酒喝完,则说明就得上限不会超过。总共存在次相遇,每次相遇存在两种可能性,如果暴力枚举所有可能性,时间复杂度为, 则无法通过。 每次相遇存在两种情况,最终需要经过次店,次花,这个约束和背包问题很类似。考虑能否使用动态规划进行优化。 在背包问题中,每件物品存在"取"和"不取"两种可能,取之后根据物品的体积和价值进行更新。 此处对应着相遇是否为“店”和“花”:
- 如果是花,则花的数量+1, 酒-1;
- 如果是店,则店的数量+1, 酒。 因此定义表示第次相遇,每次相遇需要维护店的数量(或者花的数量, 维护其中一个即可)。酒量为的方案数。
题目要求的是“遇到店次,遇到花次, 最后一次遇到的是花,正好把酒喝光”的方案数。也就相当于在前次中,遇到店次, 酒量为1的方案数,因为此时最后遇到花才能恰好喝完。
接下来考虑数组的动态转移方程:
- 初始时从家中出来有2斗酒,可以表示为边界情况;
- 如果第次相遇为花,则可以由转移过来,相当于前次相遇中遇到店铺为次、酒量为, 第次为花则店铺数量不变,酒量数量减一;
- 如果第次相遇为店,则中的必须为偶数,此时从转移过来。 根据上述分析,可以根据的奇偶性和转移方程更新数组。 实现时注意防止计算溢出。
提交代码
#include<bits/stdc++.h> #define int long long const int N = 100 + 10, mod = 1e9 + 7; int dp[2 * N][N][N]; void solve() { int n, m; std::cin >> n >> m; dp[0][0][2] = 1; for(int i = 1; i <= n + m - 1; i++) { for(int j = 0; j <= n; j++) { for(int k = 0; k <= m; k++) { if(k % 2 == 0 && j) { dp[i][j][k] = (dp[i - 1][j][k + 1] + dp[i - 1][j - 1][k / 2]) % mod; } else { dp[i][j][k] = dp[i - 1][j][k + 1]; } } } } std::cout << dp[n + m - 1][n][1] << "\n"; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(0); int t = 1; while(t--) solve(); return 0; }
- 1
信息
- ID
- 974
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 22
- 已通过
- 8
- 上传者