又开拓了一点点视野。。。。KMP的使用,想当初,看KMP看了我一个多星期啊,总算没白看。KMP中的next数组的含义我想大家应该都知道吧,如果不知道的话,还是建议去书上理解下KMP,简单说一下。KMP中的next数组表示:以当前第i个字符为结尾的字符串,与从第一个字符开始,与第i个字符相等的字符为结尾的字符串,最长能匹配的长度。举个例子:s = ababa。下标从0开始。next[0] = 0,因为它前面没有字符了。next[1] = 0.因为b和a不相等。next[2] = 1,因为a 和第一个字符相等,但是ba != ab。next[3] = 2,因为以b为结尾的ab == 以一个字符开头,以跟第i个字符相等的‘b’结尾的最长长度字符串等于ab。next[4] = 3,因为前面三个字符串aba 等于后三个字符串aba。我们把一个循环节看成一个点或者一个字符,每个点就是一个循环节。
下面这幅图,假设next[3] = 2,也就是说2号点等于1号点,3号点等于2号点,在图中就是下划线为两条的字符串等于下划线为一条的字符串。那么肯定2号点等于1号点,3号点等于2号点,那么3号点也肯定等于1号点,也就是说1,2,3号点都相等,正好满足我们的要求:一个字符串重复若干次,下面这幅图就是点1代表的字符串重复了3次。点3代表的字符串的长度就是循环节的长度。next【3】表示的就是循环节循环的次数。但是如果点3代表的字符串的长度不等于循环节的长度,那么这个字符串就不是一个周期字符串。点3的长度可以用i - next[i]+1得到,而循环次数则是(i+1)/(i - next[i]+1)
#include<stdio.h>
#include<memory>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
char str[1000005];
int next[1000005];
int main()
{
int icase = 1,n,p;
while(scanf("%d",&n),n)
{
printf("Test case #%d\n",icase++);
scanf("%s",str);
next[0] = 0;
for(int i = 1;i < n;++i)
{
p = next[i-1];
//这是求next[i]的值
while(true)
{
if(str[i] == str[p])
{
next[i] = p+1;
break;
}
if(p == 0)
{
if(str[i] != str[0])
next[i] = 0;
break;
}
p = next[p-1];
}
//根据next【i】的值跟上面的推论得出答案。
if(next[i] != 0 && next[i]%(i - next[i]+1) == 0)
printf("%d %d\n",i+1,(i+1)/(i - next[i]+1));
}
printf("\n");
}
return 0;
}