2018牛客暑假多校二 A(dp)

题目描述:

    你在健身,每秒可以走1米或跑k米,并且不能连续2秒都在跑。当它的移动距离在[L,R]之间,可以选择结束锻炼。问由多少种方案

题目分析:

    对于这个问题,因为对于每个时刻,我们可以走1米或者跑k米,因此我们不难想到这道题应该使用dp去解决。我们设dp数组dp[i][j],其中i和j分别表示到了第i米时,是由第j中方式走过来的(其中j==0代表走1米过来的,j==1代表跑k米过来的)。

    因此我们就可以分两种情况进行状态转移。不难发现,当j==0时,此时的状态即可以由前一时刻的j==0或j==1的状态分别转移过来,因此我们可以列出状态转移方程:dp[i][0]=(dp[i][0]+dp[i-1][0])%mod;dp[i][0]=(dp[i][0]+dp[i-1][1])%mod;

    同理,当j==1时,我们也可以列出状态转移方程:dp[i][1]=(dp[i][1]+dp[i-k][0])%mod;

    最后,因为我们需要求的是L到R区间的值,因此我们只需要用前缀和去维护即可。

代码:

#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
typedef long long ll;
ll sum[maxn];
ll dp[maxn][2];
const ll mod=1e9+7;
int main()
{
    int n,k;
    cin>>n>>k;
    int l,r;
    dp[0][0]=1;
    for(int i=1;i<maxn;i++){
        dp[i][0]=(dp[i][0]+dp[i-1][0])%mod;
        dp[i][0]=(dp[i][0]+dp[i-1][1])%mod;
        if(i>=k) dp[i][1]=(dp[i][1]+dp[i-k][0])%mod;
        sum[i]=(sum[i-1]+dp[i][0]+dp[i][1])%mod;
    }
    for(int i=1;i<=n;i++){
        cin>>l>>r;
        ll res=(sum[r]-sum[l-1]+mod)%mod;
        printf("%lld\n",res);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39453270/article/details/81148717