P8786 [蓝桥杯 2022 省 B] 李白打酒加强版 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
dp分析思路:
1.首先看评测数据范围,本题数据量只有一百,且题目中给出的变量有三种(绿圈中圈出的,店,花,酒),大概率就是三维的dp,所以考虑状态表示时要想三维的,那么根据经验和题意自然而然就可以想到dp[i][j][k] 为遇到店 i 次, 遇到花 j 次时,所带酒的数量为 k 的方案数
2. 在题干中找到dp的最后的结果(也可以叫出口?)和转移时需满足的条件,本题可以发现画红线部分即是dp的最后结果 即dp[n][m - 1][1],最后一步为花,即上一步为遇到i - 1朵花;酒在下一步就喝光了, 即k = 1。这里结果不能是dp[n][m][0], 因为这样不能保证最后一步是从花转移过来的
ps.另外注意一个细节,最后酒必须要喝光,而每次遇到花只会喝掉一壶,所以手中酒的数量最多为100, 所以第三维只需要枚举到100就可以了
3.接下来只需要考虑初始化和转移就好啦,转移藏在蓝线部分,我们逐步解析:
初始化dp[0][0][2] = 1; 就是初始状态
逢店加一倍:首先说明酒的数量为偶数时才可以转移,若满足转移条件显然有
if(k % 2 == 0) dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j][k / 2]) % mod;
遇花喝一斗:说明酒的数量不为0时才可以转移,转移方程为:
if(k != 0) dp[i][j][k] = (dp[i][j][k] + dp[i][j - 1][k + 1]) % mod;
4.上述步骤都分析好了,代码则呼之欲出!
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 110, mod = 1e9 + 7;
int n, m;
int dp[N][N][N];
void solve()
{
cin >> n >> m;
dp[0][0][2] = 1;
for(int i = 0; i <= 100; i ++ )
for(int j = 0; j <= 100; j ++ )
for(int k = 0; k <= 100; k ++ )
{
int &v = dp[i][j][k];
if(i && k % 2 == 0) v = (v + dp[i - 1][j][k / 2]) % mod; //i:至少要遇到1家店
if(j && k != 0) v = (v + dp[i][j - 1][k + 1]) % mod;
}
cout << dp[n][m - 1][1] << endl;
}
signed main()
{
int t = 1;
while(t -- ) solve();
return 0;
}
P8725 [蓝桥杯 2020 省 AB3] 画中漂流 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
dp分析思路:
1.找题干中有哪些变量, 乍一看 D, T, M, 这不是有三个变量吗?再仔细看下可以发现D在问题的变化过程中是个常量(再仔细想一下,这可不就是把转移条件给出了嘛!),再结合数据范围为10的3次方的量级,基本就可以确定本题是一个二维dp了,我们定义状态表示为:dp[i][j]为时间过去了i秒,体力还剩 j 的时候的方案数
2.可以发现题目中蓝线就是dp的出口,即dp[t][0]; 初始化dp[0][m] = 1; 注意第二维是m,因为最初的时候剩余体力为m!!!
3.转移条件:按状态表示和题意可知,m - j即向上游的距离,i - (m - j)为向下掉的距离,则有 if(i - (m - j) - (m - j) < D)即向下游走的距离不能大于等于D米
4.转移方程:(1)当前划:dp[i][j] += dp[i - 1][j + 1];
(2)当前不划: dp[i][j] += dp[i - 1][j];
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 3e3 + 10, mod = 1e9 + 7;
int d, t, m;
int dp[N][N]; //时间过去 i 秒, 且剩余体积为 j 的方案数
void solve()
{
cin >> d >> t >> m;
dp[0][m] = 1;
for(int i = 1; i <= t; i ++ ) //时间从第1s开始枚举
for(int j = 0; j <= m; j ++ )
{
if(i - (m - j) - (m - j) < d)
dp[i][j] = (dp[i - 1][j + 1] + dp[i - 1][j]) % mod;
}
cout << dp[t][0] << endl;
}
signed main()
{
int T = 1;
while(T -- ) solve();
return 0;
}