题目:

对于具有N个字符的给定字符串S的每个前缀(每个字符具有介于97和126之间的ASCII代码),我们想知道该前缀是否是周期性字符串。也就是说,对于每个i(2 <= i <= N),我们想要知道最大的K> 1(如果有的话),使得长度为i的S的前缀可以写为AK,即A级联K时间,对于一些字符串A.当然,我们也想知道时期K.
输入
包含几个测试用例。每个测试用例包含两行。第一行包含N(2 <= N <= 1 000 000) - 字符串S的大小。第二行包含字符串S.输入文件以一行结束,具有
数字为零。
输出
对于每个测试用例,在一行输出“测试用例#”和连续的测试用例编号;然后,对于具有周期K> 1的长度为i的每个前缀,输出前缀大小i和由单个空格分隔的周期K;前缀大小必须按递增顺序排列。在每个测试用例后打印一个空行。

样本输入

3
AAA
12
aabaabaabaab
0

样本输出

测试案例#1
2 2
3 3

测试案例#2
2 2
6 2
9 3
12 4

解题思路:这个题主要考的是KMP中next[ ]数组的理解,next[k]指的是在k之前有一个长度为next[k]的字符串是字串的前缀。这个题的意思是找字符串前缀中循环的周期最大,也就是当循环体最小的时候,循环的周期才能最多。例如样例中 2 2指的是前缀的长度aa是2,然后循环体是a,循环的周期是2.

程序代码:

#include<stdio.h>
#include<string.h>
char s[2001000];
int n,next[2001000],t;
void get();
int main()
{
int cas=1;
while(scanf("%d",&n),n!=0)
{
int i,j,k;
memset(s,0,sizeof(s));
memset(next,0,sizeof(next));
scanf("%s",s);
printf("Test case #%d\n",cas++);
get();
for(k=2;k<=n;k++)
{
t=k-next[k];//最小的循环体
// printf("<<%d %d\n",k,next[k]);
if(t!=k&&k%t==0)//当k%t为整数时,才能求最大循环周期
printf("%d %d\n",k,k/t);
}
printf("\n");
}
return 0;
}
void get()
{
int i=1,j=0;
next[0]=-1;
while(i<n)
{
if(j==-1||s[i]==s[j])
{
i++;
j++;
next[i]=j;
}
else
j=next[j];
}
/* for(i=0;i<=n;i++)
printf("%d ",next[i]);
printf("\n");*/
}