题意:给出长度为n的字符串,求每个前缀的最短循环节,如果存在大于1的循环节,输出前缀长度和循环节个数。
题解:next[i]维护位置i之前的字符串的前缀和后缀公共部分的最大长度(不包括字符串本身,否则最大长度始终是字符串本身),所以如果i % (i - next[i]) == 0,说明i - next[i]是一个循环节。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1000005;
int n, next[N];
char str[N];
void get_next() {
int pp = -1, k = 0;
next[0] = -1;
while (k < n) {
if (pp == -1 || str[pp] == str[k]) {
k++;
pp++;
next[k] = pp;
}
else
pp = next[pp];
}
}
int main() {
int cas = 1;
while (scanf("%d", &n) == 1 && n) {
scanf("%s", str);
get_next();
printf("Test case #%d\n", cas++);
for (int i = 2; i <= n; i++)
if (next[i] > 0 && i % (i - next[i]) == 0)
printf("%d %d\n", i, i / (i - next[i]));
printf("\n");
}
return 0;
}