沿前缀函数链递推每个前缀的最短非空 border,从而得到最长 period。
OJ: luogu
题目 ID: P3435
难度:提高+/省选-
标签:KMP周期递推python
日期: 2026-07-16 19:57
题意
对字符串的每个前缀求最长 period 的长度,并把这些长度求和。
思路
长度为 length 的前缀若有 border b,对应 period 长度就是 length-b。要让 period 最长,就要找最短的非空 border。
KMP 的 prefix[length] 给出最长 border,而所有更短 border 都沿 prefix 链出现。令 shortest_border[length] 表示链尾的最短非零长度,则:
text
shortest_border[length] = shortest_border[j] or j其中 j = prefix[length]。每个位置只做常数次递推。
Python 知识
x or fallback会在x == 0时取后者,正好表达“已有最短 border,否则当前 border”。- 使用 1-based 长度数组能让
prefix[j]与数学定义直接对应。 - 两个
array("i")在百万长度下仍只占约 8 MB。
代码
python
import sys
from array import array
n, word = sys.stdin.buffer.read().split()
n = int(n)
prefix = array("i", [0]) * (n + 1)
shortest_border = array("i", [0]) * (n + 1)
answer = 0
for length in range(2, n + 1):
j = prefix[length - 1]
while j and word[length - 1] != word[j]:
j = prefix[j]
if word[length - 1] == word[j]:
j += 1
prefix[length] = j
if j:
shortest_border[length] = shortest_border[j] or j
answer += length - shortest_border[length]
print(answer)复杂度
时间
总结
前缀函数只直接给最长 border,但它的链包含全部 border;在链上递推所需统计量是常见技巧。