S[i]=S[i+P] for i in [0..SIZE(S)-p-1],
then the prefix is a “period” of S. We want to all the periodic prefixs.
Input
The first line contains an integer T representing the number of cases. Then following T cases.
Each test case contains a string S (1 <= SIZE(S) <= 1000000),represents the title.S consists of lowercase ,uppercase letter.
Output
Sample Input
4 ooo acmacmacmacmacma fzufzufzuf stostootssto
Sample Output
Case #1: 3 1 2 3 Case #2: 6 3 6 9 12 15 16 Case #3: 4 3 6 9 10 Case #4: 2 9 12
题意: 求每个字符串的全部循环节。例如字符串fzufzufzuf的循环节有fzu,fzufzu,fzufzufzu,fzufzufzuf这四个。
分析: 首先有一个结论:每一个前后缀匹配都对应一个循环节,最长前后缀匹配next[len]对应最小循环节。可以用集合来粗略证明,任取一个前后缀匹配abaxxaba都存在对应的一个循环节abaxx,即前后缀匹配构成的集合包含于对应循环节的集合,同理,任取一个循环节,都存在对应的一个前后缀匹配,即循环节构成的集合包含于对应前后缀匹配的集合,因此两集合相等。有了这个结论后只需要求每个字符串所有的前后缀匹配即可。另外需要注意,循环节长度并不都是最小循环节整数倍 !如abaaaba这个字符串。
具体代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
//abaaab a
//abaa aba
//循环节长度并不都是最小循环节整数倍
//每一个前后缀匹配都对应一个循环节
//最长前后缀匹配next[len]对应最小循环节
//因此求所有循环节只需要求出所有前后缀匹配
int _next[1000005], st[1000005];
char s[1000005];
signed main()
{
int T;
cin >> T;
for(int _ = 1; _ <= T; _++)
{
scanf("%s", s+1);
int len = strlen(s+1);
for(int i = 2, j = 0; i <= len; i++)
{
while(j && s[j+1] != s[i])
j = _next[j];
if(s[j+1] == s[i])
j++;
_next[i] = j;
}
int t = len, top = 0;
while(t)
{
t = _next[t];
st[++top] = len-t;
}
printf("Case #%d: %d\n", _, top);
for(int i = 1; i <= top; i++)
printf("%d ", st[i]);
puts("");
}
return 0;
}