循环节是 KMP 算法的经典应用;
思路
假设循环节为 t,当前前缀长度为 n $\Leftrightarrow S[1, n - t] = S[t + 1, n]$,也就是前缀和后缀相等,而题目中要求 t 最小,也就是能够相等的最长的前后缀 $\Leftrightarrow$ KMP 算法中 next 数组的定义;
所以整个问题就变为遍历算出整个字符串的 next 数组的值,然后取 t = i - next[i],若 t 能整除 i 且除数大于 2 即可;
AC Code
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
const int N = 1e6 + 10;
char str[N];
int ne[N];
int main()
{
int n, T = 1;
while (scanf("%d", &n), n) {
scanf("%s", str + 1);
for (int i = 2, j = 0; i <= n; i++) {
while (j && str[i] != str[j + 1]) j = ne[j];
if (str[i] == str[j + 1]) j++;
ne[i] = j;
}
printf("Test case #%d\n", T++);
for (int i = 1; i <= n; i++) {
int t = i - ne[i];
if (i % t == 0 && i / t >= 2) {
printf ("%d %d\n", i, i / t);
}
}
puts("");
}
return 0;
}