题目链接: HDU1358

题目大意: 给一段长度为n的字符串,让你求出长度为s的完美前缀字串(含k段循环节)的字串长度len以及循环次数k,k取最大(即循环节长度取最小)

解题思路: 关于next数组性质的应用


/**
 * HDU_1358
 *
 * 输入: n以及长度为n的串。0表示输入结束
 * 输出:循环节的长度以及循环的周期(循环周期取最大)
 *
 */

/**
 *
 * next数组:
 * 当i = 0时,next[0] = -1
 * 当i > 0时, next[i] = k 表示对于到达长度为i的字符串pattern的最长相等前后缀的长度
 * ---------------------------------------------------------------------------------------
 * 也可以这么理解:
 * 设在字符串S中查找模式串T,若S[m]!=T[n],那么,取T[n]的模式函数值next[n],
 * 1.next[n]=  -1 表示S[m]和T[0]间接比较过了,不相等,下一次比较 S[m+1] 和T[0]
 * 2.next[n]=0 表示比较过程中产生了不相等,下一次比较 S[m] 和T[0]。
 * 3.next[n]= k >0 但k<n, 表示,S[m]的前k个字符与T中的开始k个字符已经间接比较相等了,下一次比较S[m]和T[k]相等吗?
 * 4.其他值,不可能。
 * 原文:https://blog.csdn.net/whyorwhnt/article/details/8883074
 * ----------------------------------------------------------------------------------------
 *
 */

 /**
 *
 * next数组的性质:
 * 如果len%(len-next[len])==0,则字符串中必存在最小循环节,且循环次数即为len/(len-next[len]);
 *
 */
#include <stdio.h>
#include <iostream>
using namespace std;

const int maxn = 1000010;
int N;
char Tmp[maxn];
int prefix[maxn];

void get_prefix_table (int n) {
    int i = 0, len = -1;
    prefix[0] = -1;
    while (i < n) {
        if(len == -1 || Tmp[i] == Tmp[len]) {  //考虑前缀长度为n的数组作为前缀表
            len++;
            i++;
            prefix[i] = len;
        }else {
            len = prefix[len];
        }
    }
}

int main() {
    int cnt = 0;
    while (~scanf("%d",&N) && N != 0) {
        scanf("%s",Tmp);
        get_prefix_table(N);
        printf("Test case #%d\n",++cnt);
        for (int i = 1; i <= N; i++) { //长度为i的串
            if(prefix[i] > 0) { //当前前后缀相同的个数>0时才有讨论
                int j = i - prefix[i];
                if(i % j == 0) {
                    printf("%d %d\n",i,i/j);
                }
            }
        }
        printf("\n");
    }

    return 0;
}