牛客网暑假训练第二场——A run(递推&前缀和)

链接:https://www.nowcoder.com/acm/contest/140/A
来源:牛客网

题目描述
White Cloud is exercising in the playground.
White Cloud can walk 1 meters or run k meters per second.
Since White Cloud is tired,it can’t run for two or more continuous seconds.
White Cloud will move L to R meters. It wants to know how many different ways there are to achieve its goal.
Two ways are different if and only if they move different meters or spend different seconds or in one second, one of them walks and the other runs.

输入描述:
The first line of input contains 2 integers Q and k.Q is the number of queries.(Q<=100000,2<=k<=100000)
For the next Q lines,each line contains two integers L and R.(1<=L<=R<=100000)
输出描述:
For each query,print a line which contains an integer,denoting the answer of the query modulo 1000000007.
示例1
输入
3 3
3 3
1 4
1 5
输出
2
7
11

题意:一个人可以从数轴0处出发,行走方式是,每秒可以走1个单位,或跑K个单位,但不能连续做跑的动作。也就是说,每次跑跑之前必须是行走动作。现在给出Q个区间询问,问从0开始出发到达区间内部有多少种走法。只要其中某一秒的动作不同即视为不同走法。

因为询问是1e6的,因此首先要经过预处理,以O(1)的复杂度直接计算出结果。首先可以递推的方式计算出到达每个点的走法。用dp【i】【0】表示行走到这个坐标的方法数,用dp【i】【1】表示跑到这个坐标的方法数,因为跑之前不能同样是跑,所以方法数是分开计算的,0和1只是表示上一步的状态。之后用dp【i】【2】求和,表示到达当前位置的总方法数。此处求成前缀和,方便询问时直接作差求区间内所有位置的方法数之和。注意要取模,而作差的过程会产生负数,因此要加上MOD再取模。

递推公式:
dp【i】【0】=dp【i-1】【0】+dp【i】【1】
即当前位置走来的方法数是上一个方法数之和
dp【i】【1】=dp【i-k】【0】
因为是跑过来的,是k步之前位置的方法数,并且因为是跑,只能由走的方法数继承。

代码如下:

#include
#define LL long long
using namespace std;
const int maxn=1e5+10;
const int inf=0x7fffffff;
const int mod = 1e9+7;
LL dp[maxn][3];
int main()
{
    int n,k;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        memset(dp,0,sizeof dp);
        dp[0][0]=1;
        dp[k][1]=1;
        dp[0][2]=2;
        for(int i=1;i<100001;i++)
        {
            dp[i][0]=(dp[i-1][0]+dp[i-1][1])%mod;
            if(i-k>0) dp[i][1]=(dp[i][1]+dp[i-k][0])%mod;
            dp[i][2]=(dp[i-1][2]+(dp[i][0]+dp[i][1])%mod)%mod;
        }
        int l,r;
        while(n--)
        {
            scanf("%d%d",&l,&r);
            printf("%lld\n",(dp[r][2]-dp[l-1][2]+mod)%mod);
        }
    }
}

你可能感兴趣的:(递归递推,动态规划)