P8786 [蓝桥杯 2022 省 B] 李白打酒加强版
题解
根据样例,观察到李白总共走 \(n+m\) 次,每一次不是遇到酒馆就是遇到花
故我们可以设 \(dp[i][0/1]\) 代表第 \(i\) 次遇到酒馆或花的方案数
但是我们发现这样的状态不好转移
故我们可以设 \(dp[i][0/1][k]\) 代表第 \(i\) 次遇到酒馆或花,还剩下 \(k\) 斗酒的方案数
但是又有一个问题,那就是无法确定这 \(i\) 次里分别遇到酒馆和花的次数,从而无法使得最后结果确保遇到酒馆 \(n\) 次,遇到花 \(m\) 次
所以我们设 \(dp[i][j][k]\) 代表当前有 \(i\) 次遇见,遇见 \(j\) 次花后还剩下 \(k\) 斗酒的方案数
code
#include<bits/stdc++.h>
using namespace std;
int dp[205][105][105]={0};//代表第i次,遇见花j次后还剩下k斗酒的方案数
int main()
{
    int n,m;
    cin>>n>>m;
    dp[0][0][2]=1;
    for(int i=1;i<=n+m;i++)
    {
        for(int j=0;j<=min(i,m);j++)
        {
            for(int k=0;k<=m;k++)//k大于m斗酒的方案不会对答案产生贡献
            {
                if(j) dp[i][j][k]=dp[i-1][j-1][k+1];//如果这一次能遇到花,即遇见花的次数大于零
                if(k%2==0&&j<i) dp[i][j][k]+=dp[i-1][j][k/2];//如果这一次能遇到酒馆,即前i次遇见花的次数小于i次
                dp[i][j][k]%=(int)(1e9+7);
            }
        }
    }
    cout<<dp[n+m-1][m-1][1]<<endl;//最后一次必须是花
    return 0;
}
                    
                
                
            
        
浙公网安备 33010602011771号