4078 01串(前缀和 + dp)

该博客介绍了如何利用前缀和和动态规划方法解决一个关于01字符串的问题。具体来说,任务是计算在给定长度范围内,能够通过特定次数的连续1替换为0操作变为全0字符串的01字符串数量。通过预处理动态规划数组f,表示长度为i的优秀字符串数量,然后计算前缀和得到s,最后对每个询问[l, r],输出s[r] - s[l-1]作为答案。代码实现中包含了状态转移方程的解释和初始化过程。
摘要由CSDN通过智能技术生成

1. 问题描述:

给定一个整数 k。现在,我们可以对 01 字符串进行如下操作:选择其中恰好 k 个连续的 1,将它们都变为 0。如果一个 01 字符串可以通过若干次上述操作,变为一个全 0 字符串,那么就称这个字符串很优秀。本题共需要回答 T 组询问,每组询问给定两个整数 l,r,并请你计算长度在 [l,r] 范围内的所有 01 字符串中优秀字符串的数量。

输入格式

第一行包含两个整数 T 和 k。接下来 T 行,每行包含两个整数 l,r。

输出格式

共 T 行,第 i 行输出第 i 组询问的答案对 10 ^ 9 + 7 取模后的结果。

数据范围

前三个测试点满足 1 ≤ T,k ≤ 10。
所有测试点满足 1 ≤ T,k ≤ 10 ^ 5,1 ≤ l ≤ r ≤ 10 ^ 5。

输入样例:

3 2
1 3
2 3
4 4

输出样例:

6
5
5
来源:https://www.acwing.com/problem/content/description/4081/

2. 思路分析:

分析题目可以知道我们需要求解区间[l,r]范围内所有 01 字符串中优秀字符串的数量,因为求解的是一个区间的值所以可以先预处理出前缀和s,s[i]表示长度小于等于i的优秀字符串的数量,这样s[r] - s[l - 1]就是答案,这样问题就转化为了如何求解每一个s[i],我们可以预处理一个f数组,其中f[i]表示长度为i的优秀字符串的数量,通过求解f[i]的前缀和最终我们就可以得到每一个s[i],所以问题就转化为了如何递推求出f列表的值,由于是一个递推的过程,f的状态表示已经确定了,f[i]表示长度为i的优秀字符串的数量,如何进行状态计算呢?状态计算一般对应集合的划分,一般是找最后一个不同点,我们可以根据当前枚举的第i位是0还是1将当前的f[i]划分为两个集合,如下图所示,当最后一位为0是时候是无法进行操作的,所以等于f(i - 1),如果最后一位为1那么将最后包含第i位连续的k个1变为0,所以与i - k的串是一一对应的,所以f(i) = f(i - 1) + f(i - k),如何确定初始状态呢?我们可以通过赋值的方法判断当前f(0)应该取什么值可以使得状态计算表达式是正确的,可以发现当f(0) = 1的时候状态计算表达式是正确的,最后计算一下f数组的前缀和那么就可以得到s,对于每一个询问[l,r],答案为s[r] - s[l - 1]。

3. 代码如下:

class Solution:
    # 前缀和 + dp
    def process(self):
        N, mod = 100010, 10 ** 9 + 7
        T, k = map(int, input().split())
        f = [0] * N
        f[0] = 1
        # 预处理f列表
        for i in range(1, N):
            f[i] = f[i - 1]
            # 只有当i >= k的时候状态i - k才是存在的
            if i >= k:
                f[i] = (f[i] + f[i - k]) % mod
        for i in range(1, N):
            # 直接将前缀和累加到f中
            f[i] = (f[i] + f[i - 1]) % mod
        for c in range(T):
            l, r = map(int, input().split())
            print((f[r] - f[l - 1]) % mod)


if __name__ == '__main__':
    Solution().process()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值