题目链接: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;
}