T01961: 前缀中的周期
KMP, http://cs101.openjudge.cn/practice/01961/
一个字符串的前缀是从第一个字符开始的连续若干个字符,例如"abaab"共有5个前缀,分别是a, ab, aba, abaa, abaab。
我们希望知道一个N位字符串S的前缀是否具有循环节。换言之,对于每一个从头开始的长度为 i (i 大于1)的前缀,是否由重复出现的子串A组成,即 AAA...A (A重复出现K次,K 大于 1)。如果存在,请找出最短的循环节对应的K值(也就是这个前缀串的所有可能重复节中,最大的K值)。
输入
输入包括多组测试数据。每组测试数据包括两行。 第一行包括字符串S的长度N(2 <= N <= 1 000 000)。 第二行包括字符串S。 输入数据以只包括一个0的行作为结尾。
输出
对于每组测试数据,第一行输出 "Test case #“ 和测试数据的编号。 接下来的每一行,输出前缀长度i和重复测数K,中间用一个空格隔开。前缀长度需要升序排列。 在每组测试数据的最后输出一个空行。
样例输入
3
aaa
12
aabaabaabaab
0样例输出
Test case #1
2 2
3 3
Test case #2
2 2
6 2
9 3
12 4题意:给定一个长度为N的字符串S,对S的每一个前缀S[1~i],如果它的最大循环次数大于1,则输出该前缀的长度和最大循环次数。
python
'''
这是一个字符串匹配问题,通常使用KMP算法(Knuth-Morris-Pratt算法)来解决。
使用了 Knuth-Morris-Pratt 算法来寻找字符串的所有前缀,并检查它们是否由重复的子串组成,
如果是的话,就打印出前缀的长度和最大重复次数。
'''
# 得到字符串s的前缀值列表
def kmp_next(s):
# kmp算法计算最长相等前后缀
next = [0] * len(s)
j = 0
for i in range(1, len(s)):
while s[i] != s[j] and j > 0:
j = next[j - 1]
if s[i] == s[j]:
j += 1
next[i] = j
return next
def main():
case = 0
while True:
n = int(input().strip())
if n == 0:
break
s = input().strip()
case += 1
print("Test case #{}".format(case))
next = kmp_next(s)
for i in range(2, len(s) + 1):
k = i - next[i - 1] # 可能的重复子串的长度
if (i % k == 0) and i // k > 1:
print(i, i // k)
print()
if __name__ == "__main__":
main()python
# 23n2300017735(夏天明BrightSummer)
case = 0
while n := int(input()):
case += 1
print(f"Test case #{case}")
s = input()
ans = {}
for i in range(1, n):
k = 1
while (k+1)*i <= n and s[:i] == s[k*i:(k+1)*i]:
k += 1
if i*k not in ans:
ans[i*k] = k
for r in ans.items():
print(*r)
print()