📅  最后修改于: 2023-12-03 15:22:56.321000             🧑  作者: Mango
在字符串处理题目中,经常会出现要求求出满足一定条件的子字符串数量或特定子串的数量。本文将介绍一道经典的字符串区间 DP 题目,即可以使用超出范围的字符来形成范围为 [L,R] 的子字符串的方式的数目。
给定一个仅包含小写字母的字符串 s 和两个小写字母字符 L、R, 给定一个整数 k,问有多少个非空子字符串是由超出区间 [L,R] 字符组成的(k 个连续的子字符串代表一个非空的子字符串)。
输入的第一行包含三个由空格分隔的整数 n,L 和 R。 长度为 n 的字符串由行末给出。
输出一行,包含所需的答案。
6 c e 1
abbcbc
9
设 $f(i)$ 表示以第 $i$ 个字符为末尾的区间中符合题目要求的子串数量。其中,$i$ 取值为 $1≤i≤n$。我们可以根据第 $i-1$ 个字符是否在区间 $[L,R]$ 内来确定 $f(i)$。
具体地:
如果第 $i-1$ 个字符不在区间 $[L,R]$ 中,则 $f(i) = f(i-1)+i-k$。这种情况下,所有以第 $i-1$ 个字符为结尾的子串均符合要求。
如果第 $i-1$ 个字符在区间 $[L,R]$ 中,则 $f(i) = f(i-1)$。这种情况下,以第 $i$ 个字符为结尾的串不符合要求,因此不能产生新的子串数量。
最终的答案为 $f(1)+f(2)+\cdots+f(n)$。时间复杂度为 $O(n)$。
使用 Python 进行自底向上的 DP 实现,可以采用列表来存储 $f(i)$ 的值。代码如下:
n, L, R, k = input().split()
n, k = int(n), int(k)
s = input().strip()
# 初始化
f = [0] * n
if L > s[0] or s[0] > R:
f[0] = 1
# 自底向上的 DP
ans = f[0]
for i in range(1, n):
if s[i] > R or s[i] < L:
f[i] = f[i-1] + i - k + 1
else:
f[i] = f[i-1]
ans += f[i]
print(ans)
该代码在样例运行时间内通过,可以 AC 此题。