【洛谷】P8786 [蓝桥杯 2022 省 B] 李白打酒加强版的题解
思路
这是一个动态规划。
状态表示:dp[i][j][k] 表示访问前 i 个位置时,恰好访问 j 个店并且酒量恰好为 k 的时候的方案数。
这个做法并不能维护所有前 $i$ 个位置恰好访问 $j$ 个店的方案数,但是题目只问最后一次遇到花且恰好把酒喝光的次数,所以对于大于 $100$ 的酒量的状态就不用转移了,因为在后面接近 100 个位置中,全看花也不能把酒喝完。
状态转移:
- 看花 : dp[i][j][k] = dp[i - 1][j][k + 1]
- 遇店 :dp[i][j][k] = dp[i - 1][j - 1][k / 2] 注意边界!不要越界。
代码
#include <bits/stdc++.h>
#define lowbit(x) x & (-x)
#define endl "\n"
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
namespace fastIO {
inline int read() {
register int x = 0, f = 1;
register char c = getchar();
while (c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
inline void write(int x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
return;
}
}
using namespace fastIO;
typedef long long ll;
ll dp[205][105][105];
const int mod = 1e9 + 7;
int main() {
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
int n, m;
cin >> n >> m;
dp[0][0][2] = 1;
for(int i = 1; i < n + m; i ++)
for(int j = 0; j <= n; j ++)
for(int k = 0; k <= 100; k ++) {
dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j][k + 1]) % mod;
if((k % 2 == 0) && j) dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j - 1][k / 2]) % mod;
}
cout << dp[n + m - 1][n][1];
return 0;
}