1 条题解

  • 0
    @ 2026-4-30 20:46:15

    题意

    将每个字符串表示为二进制串(用 0011 代替红白花)。一个字符串是“好”的,当且仅当每个由连续 00 组成的极长子串的长度都能被 kk 整除。

    思路

    使用动态规划求解。定义 nrinr_i 表示长度为 ii 的好字符串的数量。

    • 如果第 ii 个字符是 11,则前面的字符可以任意,因此方案数为 nri1nr_{i-1}
    • 如果第 ii 个字符是 00,则它必须与前面的 k1k-100 连续出现,因此方案数为 nriknr_{i-k}
      于是得到递推式:
    nri=nri1+nrik(ik)nr_i = nr_{i-1} + nr_{i-k} \quad (i \ge k) nri=1(i<k)nr_i = 1 \quad (i < k)

    算法步骤

    1. 预处理 nrnr 数组,长度为最大可能的 bib_i(记为 maxValmaxVal)。
    2. 计算前缀和 sumi=nr1+nr2++nrisum_i = nr_1 + nr_2 + \dots + nr_i
    3. 对于每个询问 (a,b)(a, b),答案为 sumbsuma1sum_b - sum_{a-1}

    复杂度分析

    • 时间复杂度:O(maxVal+t)O(maxVal + t),其中 maxValmaxVal 是所有 bib_i 的最大值,tt 是询问次数。
    • 空间复杂度:O(maxVal)O(maxVal)

    代码说明

    • 先读入 kktt,以及所有询问,找出最大的 bib_i
    • 初始化 nr0=1nr_0 = 1,然后按递推式计算 nr1nr_1nrmaxValnr_{maxVal}
    • 计算前缀和数组 sumsum
    • 对每个询问输出 sumbsuma1sum_b - sum_{a-1}
    #include<bits/stdc++.h>
    using namespace std;
    #define PF 1000000007
    #define MAXN 100005
    long long n,k,f[MAXN]={0},s[MAXN]={0},a,b; //long long
    int main(){
        cin>>n>>k;
        f[0]=1;//初始化
        for(int i=1;i<=MAXN;i++) { //dp
            f[i]+=f[i-1]%PF;
            if(i>=k)f[i]+=f[i-k]%PF;
            s[i]=(s[i-1]+f[i])%PF; //前缀和
        }
        for(int i=1;i<=n;i++) {
            cin>>a>>b;
            cout<<(s[b]-s[a-1]+PF)%PF<<endl; //输出
        }
    }
    
    
    
    • 1

    信息

    ID
    6728
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者