[蓝桥杯 2022 省 B] 李白打酒加强版
题目描述
话说大诗人李白,一生好饮。幸好他从不开车。
一天,他提着酒显,从家里出来,酒显中有酒 2
斗。他边走边唱:
无事街上走,提显去打酒。
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店 N
次, 遇到花 M
次。已知最后一次遇到的是花,他正好把酒喝光了。
请你计算李白这一路遇到店和花的顺序,有多少种不同的可能?
注意:没酒(0
斗)时遇店是合法的,加倍后还是没酒; 但是没酒时遇花是不合法的。
输入格式
第一行包含两个整数 N
和 M
。
输出格式
输出一个整数表示答案。由于答案可能很大,输出模 1000000007
(即 10^9+7
)的结果。
样例输入 #1
5 10
样例输出 #1
14
提示
【样例说明】
如果我们用 0 代表遇到花, 1 代表遇到店, 14 种顺序如下:
010101101000000 010110010010000 011000110010000 100010110010000 011001000110000 100011000110000 100100010110000 010110100000100 011001001000100 100011001000100 100100011000100 011010000010100 100100100010100 101000001010100
【评测用例规模与约定】
对于 40 %的评测用例: 1 <N, M < 10。
对于
100 %
的评测用例:1 < N, M < 100
。蓝桥杯 2022 省赛 B 组 I 题。题目分析
主要是一个DFS深搜,要从n个数中找出任意k个数相加,计算其值是否为素数。
- 和排列组合为问题相似,n选3,n选n,有几种排列的方式
- 但是这个题要的是 k 个数,所以要使用 num 来计数
- 并且还需要用一个 for 循环来控制是否需要进入 dfs
题目分析:
1.题意
设李白有酒va,有两种操作。并且最后一次操作为(2)
-
(1)va=va*2(一共n次)
-
(2)va=va-1(一共m次)
va 初始值为 2,要求经过 n+m次操作后 va=0的方案数取模。
2.状态
状态设计:dp[i][j][k]的值表示遇到i家店,j朵花,酒壶中还剩k斗酒的可能情况数;
状态转移方程:dp[i][j][k]=dp[i-1][j][k/2](i>1&&k%2==0) + dp[i][j-1][k+1](j>1);
边界设计:除了dp[0][0][2]=1,其他元素全为0;
他一共遇到店 N 次,遇到花 M 次。已知最后一次遇到的是花, 他正好把酒喝光了;所以
最后一次肯定遇到的是花,那么最后的结果便是dp[N][M-1][1];
并且酒壶中酒的容量不能超过M;
程序如下:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;//别忘记取模
int n,m,dp[105][105][105];//dp数组
int main()
{
cin>>n>>m;
dp[0][0][2]=1;
for(int i=0;i<=n;i++)
{
for(int j=0;j<=m-1;j++)
{
if(i==0&&j==0)
continue;
for(int k=0;k<=100;k++)//因为最多出现100次操作2,故va最大为100
{
if(k%2==0&&i)
dp[i][j][k]+=dp[i-1][j][k/2];//操作1
if(j)
dp[i][j][k]+=dp[i][j-1][k+1];//操作2
dp[i][j][k]%=mod;//取模
}
}
}
cout<<dp[n][m-1][1]%mod;
}