本文搬运自本人初中博客园博客,若图片加载不出来,可到原文查看:https://www.cnblogs.com/zhangtingxi/p/16203821.html

题目链接

题目

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 $ ( $ 10^{9}+7 $ ).

给定正整数 kk。称一个 0101 字符串是好的当且仅当其可以通过把连续 kk11 全部改成 00 来达到全为 00,例如 k=2k=2 时,0000110110110 是好的而 010101 不是好的。

多次询问,每次给定 l,rl,r,询问长度在 [l,r][l,r] 内的 0101 字符串有多少个是好的。由于结果可能过大,答案对 109+710^9+7 取模。

思路

dpidp_i 代表长度为 ii 的字符串的方案数,分两种情况讨论:

  1. 这格不放dpi=dpi1dp_i=dp_{i-1}.
  2. 这格,则 [ik+1,i][i-k+1, i] 区间全部得放,所以 dpi=dpikdp_i=dp_{i-k}.

综上:

dpi=dpi1+dpikdp_i=dp_{i-1}+dp_{i-k}

然后现在要求 [l,r][l, r] 区间,对 dpdp 数组作前缀和 ss,答案为 srsl1s_r-s_{l-1}.

时间复杂度 O(n)O(n).

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Problem: CF474D Flowers
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF474D
// Memory Limit: 250 MB
// Time Limit: 1500 ms

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define N 100010
//#define M
#define mo 1000000007
int n, m, i, j, k, T;
int dp[N], s[N], l, r;

signed main()
{
// freopen("tiaoshi.in","r",stdin);
// freopen("tiaoshi.out","w",stdout);
T=read(); k=read();
dp[0]=1;
for(i=1; i<=N-10; ++i)
{
dp[i]=dp[i-1]+(i<k ? 0 :dp[i-k]);
// printf("%lld\n", dp[i]);
s[i]=s[i-1]+dp[i];
dp[i]%=mo; s[i]%=mo;
}
while(T--)
{
l=read(); r=read();
printf("%lld\n", ((s[r]-s[l-1])%mo+mo)%mo);
}
return 0;
}

总结

经典dp+前缀和。

一开始想的是要记录末尾连续多少个1,然后发现太麻烦。

然后想着要记录末尾是0或1,更奇怪。

后来发现只需要讨论1还是0即可。