📌  相关文章
📜  长度为 N 的二进制字符串的计数,最多有 M 个连续的 1 或 0,或者正好是 K 次(1)

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

长度为 N 的二进制字符串计数

给定长度为 N 的二进制字符串,本文介绍如何计算满足以下限制条件的字符串数量:

  • 最多有 M 个连续的 1 或 0
  • 或者正好是 K 次
最多有 M 个连续的 1 或 0

为了计算满足最多有 M 个连续的 1 或 0 的字符串数量,我们可以使用动态规划的思想。

设 $f(i, j, k)$ 表示考虑前 $i$ 个字符,当前连续出现的字符为 $j$ (0 表示连续出现的是 0,1 表示连续出现的是 1),已经连续出现了 $k$ 个字符的方案数。

显然,$f(i, j, k)$ 可以由 $f(i-1, j, k+1)$ 和 $f(i-1, j^1, 1)$ 转移而来,其中 $j^1$ 表示 j 的相反数,即 $0 \to 1$,$1 \to 0$。

但是,由于本题限制了最多有 M 个连续的 1 或 0,因此在转移时需要判断是否超出限制,如果超出限制,则不能转移。

最终,答案即为 $\sum\limits_{j=0}^1 \sum\limits_{k=1}^M f(N, j, k)$。

代码实现如下:

N = 10
M = 3

# 初始化
f = [[[0] * (M+1) for _ in range(2)] for _ in range(N+1)]
for j in range(2):
    f[1][j][1] = 1

# 动态规划
for i in range(2, N+1):
    for j in range(2):
        for k in range(1, M+1):
            f[i][j][k] = f[i-1][j][k+1]
            if k == 1:
                f[i][j][k] += f[i-1][j^1][1]
            if k > 1:
                f[i][j][k] += f[i-1][j^1][1] - f[i-k][j^1][1]

# 计算答案
ans = sum(f[N][j][k] for j in range(2) for k in range(1, M+1))
print(ans)
正好是 K 次

为了计算正好是 K 次的字符串数量,我们可以使用组合数进行计算。

设 $g(i, k)$ 表示考虑前 $i$ 个字符,已经出现了 $k$ 次连续的字符的方案数。

显然,$g(i, k)$ 可以由 $g(i-1, k)$ 和 $g(i-1, k-1)$ 转移而来。其中,$g(i-1, k)$ 表示前 $i-1$ 个字符已经有 $k$ 个连续的字符,新添加的字符不会使得连续字符的数量增加;$g(i-1, k-1)$ 表示前 $i-1$ 个字符已经有 $k-1$ 个连续的字符,新添加的字符会使得连续字符的数量增加。

因此,我们可以得到转移方程:

$$g(i, k) = g(i-1, k) + g(i-1, k-1)$$

且 $g(1, 0) = g(1, 1) = 1$。

最终,答案为 $\sum\limits_{k=0}^K g(N, k)$。

代码实现如下:

N = 10
K = 3

# 初始化
g = [[0] * (K+1) for _ in range(N+1)]
g[1][0] = g[1][1] = 1

# 动态规划
for i in range(2, N+1):
    for k in range(K+1):
        g[i][k] = g[i-1][k] + (g[i-1][k-1] if k > 0 else 0)

# 计算答案
ans = sum(g[N][k] for k in range(K+1))
print(ans)
总结

本文介绍了如何计算长度为 N 的二进制字符串满足最多有 M 个连续的 1 或 0,或者正好是 K 次的字符串数量。对于最多有 M 个连续的限制,我们使用了动态规划的思想,而对于正好是 K 次的限制,我们使用了组合数进行计算。实际应用中,我们可以根据具体问题选择使用哪种方法进行计算。