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;
}
posted @ 2020-04-14 22:11  shuitiangong  阅读(105)  评论(0编辑  收藏  举报