definsert(self, word: str): node = self.root for ch in word: c = ord(ch) - ord("a") ifnot node.child[c]: node.child[c] = Node() node.child[c].id = len(self.nodes) self.nodes.append(node.child[c]) node = node.child[c] node.length = len(word)
defbuild(self): # O(|Σ|N),N 是節點數;若 |Σ|=26 視為常數,則為 O(N) = O(L) self.root.fail = self.root.last = self.root # BFS q = deque() for i, v inenumerate(self.root.child): if v isNone: # 添加虛擬子節點 self.root.child[i] = self.root else: v.fail = v.last = self.root q.append(v) while q: u = q.popleft() for i, v inenumerate(u.child): if v isNone: # 添加虛擬子節點 u.child[i] = u.fail.child[i] else: # 失配位置 v.fail = u.fail.child[i] # 上一個一定是某個 word 結尾的節點 v.last = v.fail if v.fail.length else v.fail.last q.append(v)
classMatrix: def__init__(self, mat): self.mat = mat
def__mul__(self, other): A, B = self.mat, other.mat assertlen(A[0]) == len(B) n, p, m = len(A), len(B), len(B[0]) res = [[0] * m for _ inrange(n)] for i inrange(n): ri = res[i] Ai = A[i] for k inrange(p): if Ai[k] == 0: continue x = Ai[k] Bk = B[k] for j inrange(m): ri[j] = (ri[j] + x * Bk[j]) % MOD return Matrix(res)
def__pow__(self, k): assertlen(self.mat) == len(self.mat[0]) n = len(self.mat) res = Matrix([[int(i == j) for j inrange(n)] for i inrange(n)]) base = self while k > 0: if k & 1: res *= base base *= base k >>= 1 return res
defmul_pow(self, k, x): assertlen(self.mat[0]) == len(x.mat) res = x base = self while k > 0: if k & 1: res = base * res base *= base k >>= 1 return res
ac = AhoCorasick() for _ inrange(k): ac.insert(input().strip()) ac.build()
nodes = ac.nodes m = len(nodes)
bad = [False] * m for node in nodes: if node.length > 0or node.last != ac.root: bad[node.id] = True
# T[v][u] 表示從 u 狀態加入一個字元後,到達 v 狀態的方案數 T = [[0] * m for _ inrange(m)] for u in nodes: if bad[u.id]: continue for v in u.child: if bad[v.id]: continue T[v.id][u.id] += 1
T = Matrix(T) f = Matrix([[1] if i == 0else [0] for i inrange(m)]) f = T.mul_pow(n, f)
ans = sum(f[i][0] for i inrange(m) ifnot bad[i]) % MOD print(ans)
if __name__ == "__main__": solve()
寫在最後
Cover Image Credit
The cover image was created by @梅原生(せい). All rights belong to the original artist.
It is used here only as a non-commercial cover illustration for this note. I do not claim ownership of the artwork.
If you are the copyright holder and believe this usage is inappropriate, please contact me by email or leave a comment. I will remove the image promptly.