HDU 1358 Period (KMP)
题目链接:HDU 1358 Period
题目大意:
给定字符串,求出所有有重复的前缀,并输出前缀的大小,以及重复的周期(次数)。
思路
运用 kmp 的next数组(未优化版本)求得
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | |
字符串 | a | a | b | a | a | b | a | a | b | a | a | b | |
next [ ] | -1 | 0 | 1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
next[ i ]代表了 i前面位置组成的字符串他的前缀后缀相匹配的次数,并且 next[ i ],也记录了当前后缀上一次出现的位置。
真是神奇。
next [ 5] = 2 ,也就是说 a a b a a中前缀 后缀匹配次数为2 , 也就是说 前“aa” 和 后“aa” 匹配 , 而 位置 2 正好就是 前缀“aa” 的后一个位置。
源代码
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <set> #include <map> using namespace std; string a; const int maxn = 1000000 + 10; int nextv[maxn]; int len; void getnext(){ int i = 0,j=-1; nextv[0] = -1; while(i<len){ if(j == -1 || a[i] == a[j]) nextv[++i] = ++j; else j = nextv[j]; } } int main(){ int n; int cas = 1; while(scanf("%d",&n)!=EOF && n){ getchar(); printf("Test case #%d\n",cas++); getline(cin,a); len = a.length(); getnext(); // for(int i=0;i<=len;i++) // printf("%d ",nextv[i]); // cout<<endl; for(int i=2;i<=len;i++){ int lengtha = i - nextv[i]; //循环节的长度 if(lengtha != i &&i % lengtha == 0){ //如果的确重复出现 printf("%d %d\n",i,i/lengtha); } } printf("\n"); } return 0; }