1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| import sys from collections import deque from typing import Optional
class TrieNode: def __init__(self): self.ch: list[Optional["TrieNode"]] = [None] * 26 self.idxes: list[int] = [] self.visit_cnt: int = 0 self.fail: Optional["TrieNode"] = None self.in_degree: int = 0
__slots__ = "ch", "idxes", "visit_cnt", "fail", "in_degree"
def ac_automation(patterns: list[str], text: str) -> list[int]: root = TrieNode() nodes: list[TrieNode] = [root]
for idx, pattern in enumerate(patterns): cur = root for c in pattern: i = ord(c) - ord("a") if cur.ch[i] is None: nodes.append(TrieNode()) cur.ch[i] = nodes[-1] cur = cur.ch[i] cur.idxes.append(idx)
root.fail = root q = deque(x for x in root.ch if x is not None) for x in q: x.fail = root root.ch = [x if x is not None else root for x in root.ch] while q: cur = q.popleft() for i in range(26): if cur.ch[i] is None: cur.ch[i] = cur.fail.ch[i] else: cur.ch[i].fail = cur.fail.ch[i] cur.fail.ch[i].in_degree += 1 q.append(cur.ch[i])
cur = root for c in text: i = ord(c) - ord("a") cur = cur.ch[i] cur.visit_cnt += 1
occurrences = [0] * len(patterns) q = deque(x for x in nodes if not x.in_degree) while q: cur = q.popleft() for idx in cur.idxes: occurrences[idx] = cur.visit_cnt cur.fail.visit_cnt += cur.visit_cnt cur.fail.in_degree -= 1 if not cur.fail.in_degree: q.append(cur.fail)
return occurrences
input = lambda: sys.stdin.readline().rstrip("\r\n")
N = int(input()) patterns = [input() for _ in range(N)] text = input() print(*ac_automation(patterns, text), sep="\n")
|