链接:https://ac.nowcoder.com/acm/contest/29813/K 来源:牛客网

yezzz 近日沉迷一款名为“打 Boss”的摸鱼小游戏,众所周知,游戏里面会有轻击和重击,轻击扣 Boss 一滴 血,重击扣两滴血。现在想知道若有nn轮回合,问扣 Bossmm滴血的方案数。 注意:每一回合有三种选择,轻击,重击或不攻击。

输入描述:

第一行一个整数t(1 ≤ t ≤ 10^4 )t(1≤t≤104),表示有tt组测试数据。

接下来tt行,每行两个整数 n, m,(1 ≤ n, m ≤ 3000)n,m,(1≤n,m≤3000)表示nn轮攻击,mm滴血。

输出描述:

输出t行,第i行共包含一个整数,为第ii组测试数据的答案(由于答案过大,答案请对 1000000007 取模)。

首先是分析题目,每个回合可以有三个选择,问的是扣血的方案数

个人的感觉的话像是01背包的变形问题。

可以设置一个二维数组

int dp[3003][3003];

其实dp有时候没想象的那么难,这个题跟01背包其实就是把所有的可能都列举出来

01背包的二维数组dp[i][j]表示的是前i个物品时容量为j时装的体积

那这个稍微换一个思路就是可以分析成dp[i][j] 前i个回合,扣j滴血的方案数

然后可以从前开始分析,有三个选择。

选择不攻击的时候是这样的

dp[i][j]=(dp[i][j]+dp[i-1][j])%mod;

选择轻击的时候,也可以想到,因为问的是i回合扣了j血的方案数,所以就是i-1回合时,扣了j-1滴血的时候再来一个轻击就是得到了方案数

dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod;

由上可得,重击时跟轻击时的分析差不多,可以得到

dp[i][j]=(dp[i][j]+dp[i-1][j-2])%mod;

再把上面的整合一下就是本题的状态转移方程

dp[i][j]=(dp[i-1][j-1]+dp[i-1][j-2]+dp[i-1][j])%mod;

不过有的时候要判定一下,因为j=1的时候j-2就小于0了

然后的话再放一下ac代码

#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
long dp[3003][3003];//dp[i][j]表示i回合打j滴血的方案
int main()
{
    int t;
    cin>>t;
    dp[1][1]=1,dp[1][2]=1;
    for(int i=2;i<=3000;i++)
        dp[i][1]=(dp[i-1][1]+1)%mod;
    for(int i=2;i<=3000;i++)
        dp[i][2]=(dp[i-1][1]+dp[i-1][2]+1)%mod;
    for(int i=2;i<=3000;i++){
        for(int j=3;j<=3000;j++){
            dp[i][j]=(dp[i-1][j-1]+dp[i-1][j-2]+dp[i-1][j])%mod;
        }
    }
    while(t--){
        int n,m;
        cin>>n>>m;
        cout<<dp[n][m]<<endl;
    }
}