AcWing 状态机DP相关问题 1052. 设计密码 KMP状态机模型,有点难想到

from typing import List


def getKmpNext(data: List) -> List[int]:
    next = [0 for _ in range(len(data))]
    next[0] = -1
    j, k = 0, -1

    while j < len(data) - 1:
        if k == -1 or data[j] == data[k]:
            j, k = j + 1, k + 1
            next[j] = k
        else:
            k = next[k]

    return next


# 预处理先把状态转移的边算出来
N = int(input())
edge = {}
T = input()
next = getKmpNext(T)
for j in range(len(T)):
    for ch in 'abcdefghijklmnopqrstuvwxyz':
        if ch == T[j]:
            edge[(j, ch)] = j + 1
        else:
            jj = j
            while T[jj] != ch:
                jj = next[jj]
                if jj == -1:
                    break
            edge[(j, ch)] = jj + 1

M = len(T)

# dp(i, j)表示的是原字符串和模式串的KMP匹配位置为i和j这样一种匹配状态是多少个可能的j的变化序列构造出来的
# 只要有一个j的变化序列能够构造出(i, j)这种状态,就存在一种长度为i的不包含子串T的字符串,
# 同一个i所有的dp(i,j)加起来等价于所有不包含模式串的长度为i-1的原字符串数量
dp = [[0] * M for _ in range(N + 1)]
dp[0][0] = 1

for i in range(N):
    for j in range(M):
        for ch in 'abcdefghijklmnopqrstuvwxyz':  # 枚举i位置的字符的26种可能
            next_j = edge[(j, ch)]
            if next_j >= 0 and next_j < M:
                dp[i + 1][next_j] += dp[i][j]

print(sum(dp[N]) % 1000000007)

猜你喜欢

转载自blog.csdn.net/xiaohaowudi/article/details/107719595
今日推荐