第十三届蓝桥杯 2022年4月 省赛 C/C++ B组 I 题 李白打酒加强版 题解 DP

I 李白打酒加强版 (25分)

【问题描述】

话说大诗人李白,一生好饮。幸好他从不开车。
一天,他提着酒壶,从家里出来,酒壶中有酒 2 22 斗。他边走边唱:
无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店 N NN 次,遇到花 M MM 次。已知最后一次遇到的是花,他正好把酒喝光了。
请你计算李白这一路遇到店和花的顺序,有多少种不同的可能?
注意:壶里没酒( 0 00 斗) 时遇店是合法的,加倍后还是没酒;但是没酒时遇花是不合法的。

【输入格式】

第一行包含两个整数 N NN 和 M MM.

【输出格式】

输出一个整数表示答案。由于答案可能很大,输出模 1000000007 10000000071000000007 的结果。

【样例输入】

5 10
1

【样例输出】

14
1

【样例说明】

如果我们用 0 00 代表遇到花,1 11 代表遇到店,14 1414 种顺序如下:
010101101000000 010101101000000010101101000000
010110010010000 010110010010000010110010010000
011000110010000 011000110010000011000110010000
100010110010000 100010110010000100010110010000
011001000110000 011001000110000011001000110000
100011000110000 100011000110000100011000110000
100100010110000 100100010110000100100010110000
010110100000100 010110100000100010110100000100
011001001000100 011001001000100011001001000100
100011001000100 100011001000100100011001000100
100100011000100 100100011000100100100011000100
011010000010100 011010000010100011010000010100
100100100010100 100100100010100100100100010100
101000001010100 101000001010100101000001010100

【评测用例规模与约定】

对于 40 % 40%40% 的评测用例:1 ≤ N , M ≤ 10 1 ≤ N, M ≤ 101≤N,M≤10。
对于 100 % 100%100% 的评测用例:1 ≤ N , M ≤ 100 1 ≤ N, M ≤ 1001≤N,M≤100。

题解

DP

dp[i][j][k]表示遇到i个酒店和j朵花现在还剩k壶酒的所有路线数

只遇到酒店和只遇到花的情况需要初始化一下。

代码
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int N = 110;
typedef long long ll;
ll dp[N][N][N];
int n, m;
#define ll long long
ll qm(int a, int b){
    int ans = 1;
    while(b) {
        if(b & 1) ans = ans * a ;     
        a = a * a ;                   
        b >>= 1;                         
    }
    return ans;
}
int main()
{
    cin >> n >> m;
    dp[0][0][2] = 1; //只遇到花
    dp[0][1][1] = 1; //只遇到花
    for(int i = 0; i <= 7 ; i ++ )
    {
        dp[i][0][qm(2, i + 1)] = 1; //初始化  将只遇到酒店的 初始化为1
    }
    for(int i = 1; i <= n; i  ++ )
        for(int j = 1; j <= m ; j ++ )
            for(int k = 0; k <= m; k ++  )
            {
                if(k % 2 == 0)
                dp[i][j][k] = (dp[i - 1][j][k / 2] + dp[i][j - 1][k + 1] ) % mod ; //遇到酒店 或者 遇到 花
                else 
                dp[i][j][k] = dp[i][j - 1][k + 1];  //只能遇到花

            }
    cout << dp[n][m - 1][1]  << endl;  
    return 0;
}

算法2

(暴力枚举) DFS 只能过两个样例

记住最后两次肯定都是花

代码
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
int n, m;
ll sum = 0;

void  dfs(int x, int y, int s) {
    if (x == n && y == m - 2  && s == 2) {
        sum ++;
        sum = sum % mod;
    }
    if (x < n) dfs(x + 1, y, s * 2);
    if (s > 0 && y < m - 2) dfs(x, y + 1, s - 1);
}
int main() {
    cin >> n >> m;
    dfs(0, 0, 2);
    cout << sum << endl;
    return 0;
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值