HDU 1358 Period(kmp求循环节)
题目链接
题目大意:给一个长度为\(n\)的字符串\(s\),升序输出\(s\)的所有前缀中具有循环节的前缀并且输出循环次数。
\(kmp\)的\(next\)数组存储了当前位置公共前后缀的大小,同样也是失配之后往前跳转的长度。每次失配的时候,指针会从一个(与某个前缀相同的)公共后缀的尾部跳转到前一个(与某个前缀相同的)公共后缀尾部,假设两个公共后缀尾部相隔一个循环节的话(即\(i-next[i]\),循环节出现次数大于\(1\)),那么它们的距离一定能被串的大小整除。具体可以看这里
const int maxn = 2e6+10;
char str[maxn];
int n, nxt[maxn];
void get_next() {
int i = 0, j = -1;
nxt[i] = j;
while(i<n) {
while(~j && str[i]!=str[j]) j = nxt[j];
nxt[++i] = ++j;
}
}
int main(void) {
int kase = 1;
while(~scanf("%d", &n) && n) {
scanf("%s", str);
get_next();
printf("Test case #%d\n", kase++);
for (int i = 2; i<=n; ++i) {
int tmp = i-nxt[i]; //tmp为一个链节的大小
if (nxt[i]>=1 && !(i%tmp)) printf("%d %d\n", i, i/tmp); //nxt[i]=0说明没有公共前后缀,不做计算
nxt[i] = 0;
}
putchar(endl);
}
return 0;
}