Flowers(0-1背包+取余运算 线性dp)

We saw the little game Marmot made for Mole’s lunch. Now it’s Marmot’s dinner time and, as we all know, Marmot eats flowers. At every dinner he eats some red and white flowers. Therefore a dinner can be represented as a sequence of several flowers, some of them white and some of them red.

But, for a dinner to be tasty, there is a rule: Marmot wants to eat white flowers only in groups of size k.

Now Marmot wonders in how many ways he can eat between a and b flowers. As the number of ways could be very large, print it modulo 1000000007 (109 + 7).

Input
Input contains several test cases.

The first line contains two integers t and k (1 ≤ t, k ≤ 105), where t represents the number of test cases.

The next t lines contain two integers ai and bi (1 ≤ ai ≤ bi ≤ 105), describing the i-th test.

Output
Print t lines to the standard output. The i-th line should contain the number of ways in which Marmot can eat between ai and bi flowers at dinner modulo 1000000007 (109 + 7).

Examples
Input
3 2
1 3
2 3
4 4
Output
6
5
5
Note
For K = 2 and length 1 Marmot can eat ®.
For K = 2 and length 2 Marmot can eat (RR) and (WW).
For K = 2 and length 3 Marmot can eat (RRR), (RWW) and (WWR).
For K = 2 and length 4 Marmot can eat, for example, (WWWW) or (RWWR), but for example he can’t eat (WWWR).
题目分析:
我们先设dp[n]表示长度为n时所有可能的组成数量。那么现在分析末尾的几种可能性。

  1. 末尾是白花时,那么前面连续k位肯定都是百花,那么这个状态就从长度为n-k这个状态转移而来,那么就满足这个式子,dp[n]=dp[n-k]
  2. 当然除了白花只能是红花了,红花就没那么矫情了,她不管你前面是啥,是红是白他都无所谓,那么他的状态就从长度n-1处转移而来,满足这个式子,dp[n]=dp[n-1]
  3. 综合一下,就是这么一个状态转移方程:dp[n]=dp[n-1]+dp[n-k]
    注意每次写完后取余。
    然后就可以对所要求的区间求和了,ans[n]=dp[n]+ans[n-1]
    最后答案就是ans[r]-ans[l-1].但是这里有个问题,ans是取余之后的数值,作差的话可能会出现负数,那么就加上mod再取余,避免了负数的情况。
    代码:
#include<iostream>
using namespace std;
const long long mod=1e9+7;
const int N=2e5+10;
long long dp[N],ans[N];
int main()
{
    int n,k;
    cin>>n>>k;
    dp[0]=1;
    for(int i=1;i<=100001;i++)
    {
        if(i>=k)
        dp[i]=(dp[i-k]+dp[i-1])%mod;
        else dp[i]=dp[i-1]%mod;
    }
    for(int i=1;i<=100001;i++)
        ans[i]=(dp[i]+ans[i-1])%mod;
    while(n--)
    {
        int l,r;
        cin>>l>>r;
        cout<<(ans[r]-ans[l-1]+mod)%mod<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值