📅  最后修改于: 2023-12-03 14:58:18.902000             🧑  作者: Mango
这是一道GATE CS 1999的考题,是一道关于递推和组合计数的问题。
给定一个长度为 $n$ 的字符串 $w$,其中字符集为 ${1, 2, \cdots , k}$,定义 $w$ 的“好的子串”为一个连续的子串,其中每个数字出现的次数都相同。例如,如果 $w$ 为“112223334”,则它的好的子串为“222”和“3334”。
现在,我们定义 $F(i,j)$ 为以 $i$ 结尾且长度为 $j$ 的好的子串的个数。写一个递推式来计算 $F(i,j)$。
一般情况下,如果要递推计算某个问题的结果,那么我们通常要求出问题与子问题之间的关系。对于这道题,我们可以考虑如下两种情况:
注意,用递推式计算 $F(i,j)$ 的时候,需要考虑 $j=k$ 的情况,即 $F(i,k)$ 表示一个长度为 $k$ 的“好的子串”,它一定是由相同的数字组成的。因此,在初始化的时候,$F(i,k)$ 的值应该等于 $1$ 或 $0$。
最终,我们的目标就是计算 $F(n,1)+F(n,2)+\cdots+F(n,k)$ 的值,它等价于计算长度为 $n$ 的字符串 $w$ 中包含多少个“好的子串”。
以下是实现 $F(i,j)$ 的python代码,使用二维数组 $dp$ 记录。
def count_good_substrings(w, k):
n = len(w)
dp = [[0] * (k + 1) for _ in range(n + 1)]
# 初始化,计算最后一个数字出现的前缀子串的个数
for i in range(1, n + 1):
dp[i][1] = 1 if i == 1 or w[i - 1] != w[i - 2] else 0
# 递推计算 F(i,j)
for i in range(2, n + 1):
for j in range(2, k + 1):
if w[i - 1] != w[i - j] or dp[i - 1][j] == 0:
dp[i][j] = 0
else:
dp[i][j] = dp[i - 1][j] + 1
# 计算所有长度为 j 的好的子串的个数之和
return sum(dp[n][j] for j in range(1, k + 1))
以上就是本题的详细解答,如果还有不清楚的地方,欢迎在评论区提问。