📌  相关文章
📜  字符串被n整除的子序列数(1)

📅  最后修改于: 2023-12-03 15:09:22.182000             🧑  作者: Mango

字符串被n整除的子序列数

介绍

本文将介绍如何计算给定字符串中被n整除的子序列数。子序列定义为原始字符串中任意个数的字符按照原始顺序排列组成的字符串,不一定连续。

例如,对于字符串"1234"和n=3,它的子序列有"1"、"2"、"3"、"4"、"12"、"13"、"14"、"23"、"24"、"34"、"123"、"124"、"134"、"234"和"1234",其中能被3整除的有"123"和"132",因此答案为2。

思路

我们可以使用动态规划的方法来解决这个问题。我们定义一个二维数组dp,其中dp[i][j]表示前i个字符中有多少个子序列能被n整除,最终答案为dp[n][0]。

我们可以根据当前字符的状态来更新dp数组的状态。对于第i个字符,它可以选择加入前面一个子序列,或者自己单独成为一个子序列。

如果选择加入前面一个子序列,那么当前状态为dp[i-1][(j-k*10^i)%n],其中k为前一个子序列的值,i为当前字符位置。

如果选择自己单独成为一个子序列,那么当前状态为dp[i-1][ j ]。

两种情况取和就是dp[i][j]的值,即:

dp[i][j] = dp[i-1][j] + dp[i-1][(j-k*10^i)%n]

其中需要特别注意的是:

  1. 如果当前字符为0,那么单独成为一个子序列时只能产生1个子序列;
  2. 初始状态为dp[0][0]=1。
代码
def count_subsequences(s: str, n: int) -> int:
    # 初始化 dp 数组
    dp = [[0] * n for _ in range(len(s) + 1)]
    dp[0][0] = 1

    for i in range(1, len(s) + 1):
        k = int(s[i - 1])
        dp[i][k % n] += 1  # 当前字符单独成为一个子序列的情况
        for j in range(n):
            dp[i][j] += dp[i - 1][j]  # 前一个子序列不能被当前字符整除的情况
            dp[i][(j * 10 + k) % n] += dp[i - 1][j]  # 前一个子序列能被当前字符整除的情况

    return dp[-1][0]
参考文献