Period hdu 1358 KMP的使用

来源:互联网 发布:php laravel 入门教程 编辑:程序博客网 时间:2024/06/17 15:23

又开拓了一点点视野。。。。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;}


原创粉丝点击