蓝桥杯急救计划 day2 (2) dp专项

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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>