题目描述:
你在健身,每秒可以走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
",res);
}
return 0;
}