📅  最后修改于: 2023-12-03 14:57:06.113000             🧑  作者: Mango
这篇文章将介绍如何编写一个程序,来统计一个字符串中能被 8 整除但不能被 3 整除的子串数。
我们将采用动态规划的思路来解决这个问题。具体地,我们定义 $f_{i,j}$ 为以第 $i$ 个字符为结尾的长度为 $j$ 的子串能否被 8 整除但不能被 3 整除。显然, $f_{i,1}$ 等于该字符能否被 8 整除但不能被 3 整除,即 $f_{i,1}=[\text{该字符能被 8 整除但不能被 3 整除}]$。
根据 $f_{i,1}$ 和 $f_{i,j-1}$,我们可以得到 $f_{i,j}$,由于 $f_{i,j}$ 只与 $f_{i,j-1}$ 有关,因此可以采用滚动数组来优化空间复杂度。具体地,状态转移方程为:
$$f_{i,j}=f_{i,j-1}\times 10+f(i-j+1,i)$$
其中 $f(l,r)$ 表示 $[l,r]$ 这个子串所表示的数字。上式的解释是:把 $[i-j+1,i]$ 这个子串添加到 $[i-j,i-1]$ 这个子串的后面,此时的子串为 $[i-j,i]$,判断它是否能被 8 整除但不能被 3 整除。
最终的答案为 $f_{1,n}+f_{2,n}+\cdots+f_{n,n}$(即所有以第 $i$ 个字符为结尾的子串的和)。
下面是基于上述思路的代码实现,使用 Python 语言编写:
def solve(s):
n=len(s)
f=[0]*n
ans=0
for i in range(n):
f[i]=(s[i]%8==0 and s[i]%3!=0)
ans+=f[i]
for j in range(2,n+1):
for i in range(n-j+1):
f[i]=f[i]*10+s[i+j-1]
if j%3!=0 and f[i]%8==0:
ans+=1
return ans
我们使用下面的示例来测试我们的程序:
assert solve("1506")==3
assert solve("228")==4
assert solve("2333")==0
assert solve("99991")==1
assert solve("993381")==2
至此,我们提出的问题得到了解决。这篇文章中介绍了使用动态规划的思路来解决一个字符串中能被 8 整除但不能被 3 整除的子串数的问题,同时也给出了代码的实现。