KMP
\831. KMP字符串
https://www.acwing.com/problem/content/833/
def get_ne(s):
ne = [0]*len(s)
j = 0
for i in range(2,N+1):
while j and s[i]!=s[j+1]:
j = ne[j]
if s[i]==s[j+1]:
j += 1
ne[i] = j
return ne
N = int(input())
s = [0]+list(input())
M = int(input())
p = [0]+list(input())
ne = get_ne(s)
print(ne)
res = []
j = 0
for i in range(1,M+1):
while j>0 and s[j+1]!=p[i]:
j = ne[j]
if p[i]==s[j+1]:
j += 1
if j == N:
res.append(i-N)
j = ne[j]
print(*res)
Trie
\835. Trie字符串统计
https://www.acwing.com/problem/content/837/
N = int(input())
idx = 0
trie = [[0]*(26) for i in range(100010)]
cnt = [0 for i in range(100010)]
def insert(s):
global idx
net = 0
for e in s:
if not trie[net][ord(e)-97]:
idx += 1
trie[net][ord(e)-97] = idx
net = trie[net][ord(e)-97]
cnt[net] += 1
def query(s):
net = 0
for e in s:
if not trie[net][ord(e)-97]:
return 0
net = trie[net][ord(e)-97]
return cnt[net]
for i in range(N):
Q,x = input().split()
if Q=='I':
insert(x)
elif Q=='Q':
print(query(x))
\143. 最大异或对
https://www.acwing.com/problem/content/145/
N = int(input())
lis = list(map(int,input().split()))
trie = [[0,0] for i in range(N*31)]
idx = 0
def insert(x):
global idx
net = 0
for i in range(31,-1,-1):
u = x>>i&1
if not trie[net][u]:
idx += 1
trie[net][u] = idx
net = trie[net][u]
# 选最大的异或对
def query(x):
net = 0
res = 0
for i in range(31,-1,-1):
u = x >> i & 1
if trie[net][not u]:
res = res*2+1
net = trie[net][not u]
else:
res = res*2+0
net = trie[net][u]
return res
for li in lis:
insert(li)
max_n = 0
for li in lis:
max_n = max(max_n,query(li))
print(max_n)
AC自动机
\1282. 搜索关键词
https://www.acwing.com/problem/content/1284/
from collections import deque
def insert(s):
global idx
t = 0
for c in s:
if not trie[t][ord(c)-97]:
idx += 1
trie[t][ord(c)-97] = idx
t = trie[t][ord(c)-97]
cnt[t] += 1
def build():
dq = deque()
for i in range(26):
if trie[0][i]:
dq.append(trie[0][i])
while dq:
t = dq.popleft()
for i in range(26):
c = trie[t][i]
if not c:
trie[t][i] = trie[ne[t]][i]
else:
ne[c] = trie[ne[t]][i]
dq.append(c)
T = int(input())
for _ in range(T):
n = int(input())
strs = []
for i in range(n):
strs.append(input())
pages = input().strip()
trie = [[0] * 26 for i in range(50 * n + 10)]
idx = 0
cnt = [0] * (50 * n + 10)
# 构建字典树
for s in strs:
insert(s)
# 构建next数组
ne = [0 for i in range(50 * n + 10)]
build()
# print(ne)
res = 0
j = 0
for i in range(len(pages)):
t = ord(pages[i]) - 97
j = trie[j][t]
p = j
while p:
# print(res)
res += cnt[p]
cnt[p] = 0
p = ne[p]
print(res)
\1285. 单词(ac自动机+拓扑排序)
https://www.acwing.com/problem/content/1287/
from collections import deque
def insert(s):
global idx
t = 0
for c in s:
if not trie[t][ord(c)-97]:
idx += 1
trie[t][ord(c)-97] = idx
t = trie[t][ord(c)-97]
# 走到这个点的路径数
cnt[t] += 1
idx_word.append(t)
def build():
dq = deque()
for i in range(26):
if trie[0][i]:
top_sort_lis.append(trie[0][i])
dq.append(trie[0][i])
while dq:
t = dq.popleft()
for i in range(26):
c = trie[t][i]
if not c:
trie[t][i] = trie[ne[t]][i]
else:
ne[c] = trie[ne[t]][i]
top_sort_lis.append(c)
dq.append(c)
n = int(input())
trie = [[0]*26 for i in range(1000010)]
idx = 0
cnt = [0 for i in range(1000010)]
ne = [0 for i in range(1000010)]
idx_word = []
# 记录BFS添加的顺序,用于拓扑排序
top_sort_lis = []
for i in range(n):
insert(input())
build()
for i in range(idx-1,-1,-1):
cnt[ne[top_sort_lis[i]]] += cnt[top_sort_lis[i]]
for i in range(n):
print(cnt[idx_word[i]])
\1. 奇怪的编程
https://www.lanqiao.cn/problems/4270/learning/?page=1&first_category_id=1&name=%E5%A5%87%E6%80%AA%E7%9A%84%E7%BC%96%E7%A8%8B
from collections import deque
# 构建trie
def insert(s):
global idx,longest
u = 0
for c in s:
if not trie[u][ord(c)-97]:
idx += 1
trie[u][ord(c)-97] = idx
u = trie[u][ord(c)-97]
cnt[u] = 1
cnt_length[u] = len(s)
longest = max(longest,len(s))
# 构建ac自动机next数组
def get_ne():
dq = deque()
for i in range(26):
if trie[0][i]:
dq.append(trie[0][i])
while dq:
u = dq.popleft()
for i in range(26):
c = trie[u][i]
if not c:
trie[u][i] = trie[ne[u]][i]
else:
ne[c] = trie[ne[u]][i]
dq.append(c)
n,k = map(int,input().split())
trie = [[0]*26 for i in range(450)]
idx = 0
ne = [0 for i in range(450)]
# 以当前节点字母结尾的有一个单词
cnt = [0 for i in range(450)]
# 以当前节点字母结尾的单词的长度
cnt_length = [0 for i in range(450)]
# 保存所有编码集D中最长的
longest = 0
for i in range(n):
insert(input())
get_ne()
res = []
for _ in range(k):
ipt = input()
j = 0
# 表示到第i的位置是否能匹配到单词
dp = [0]*(10010)
dp[0] = 1
last = 0
for i in range(len(ipt)):
j = trie[j][ord(ipt[i])-97]
p = j
while p:
# 如果当前位置能匹配到一个单词则更新last
if cnt[p] and dp[i+1-cnt_length[p]]:
dp[i+1] = 1
last = i+1
break
p = ne[p]
if last + longest < i+1:
break
res.append(last)
# print(ne)
print(*res,sep='\n')