Period
Time Limit: 3000MS | Memory Limit: 30000K | |
Total Submissions: 16431 | Accepted: 7886 |
Description
For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want to know whether the prefix is a periodic string. That is, for each i (2 <= i <= N) we want to know the largest K > 1 (if there is one) such that the prefix of S with length i can be written as A
K ,that is A concatenated K times, for some string A. Of course, we also want to know the period K.
Input
The input consists of several test cases. Each test case consists of two lines. The first one contains N (2 <= N <= 1 000 000) – the size of the string S.The second line contains the string S. The input file ends with a line, having the
number zero on it.
Output
For each test case, output “Test case #” and the consecutive test case number on a single line; then, for each prefix with length i that has a period K > 1, output the prefix size i and the period K separated by a single space; the prefix sizes must be in increasing order. Print a blank line after each test case.
Sample Input
3 aaa 12 aabaabaabaab 0
Sample Output
Test case #1 2 2http://write.blog.csdn.net/postedit?ref=toolbar 3 3 Test case #2 2 2 6 2 9 3 12 4
此题为2406的升级版,重在理解KMP中next[i]和i-next[i]的用法,(2406为len-next[len]),next[i]即为到下标+1为止,是否与原串的从头开始有没有相同的子串,如果无,则为0,i-len[i]则为从0开始到i的匹配的相同子串的长度,换成len后,则为最长的那个。
大意:
定义字符串A,若A最多由n个相同字串s连接而成,则A=s^n,如”aaa” = “a”^3,”abab” = “ab”^2
“ababa” = “ababa”^1
给出一个字符串A,求该字符串的所有前缀中有多少个前缀SA= s^n(n>1)
输出符合条件的前缀长度及其对应的n
如aaa
前缀aa的长度为2,由2个’a’组成
前缀aaa的长度为3,由3个”a”组成
分析:KMP
若某一长度L的前缀符合上诉条件,则
1.next[L]!=0(next[L]=0时字串为原串,不符合条件)
2.L%(L-next[L])==0(此时字串的长度为L/next[L])
对于2:有str[0]….str[next[L]-1]=str[L-next[L]-1]…str[L-1]
=》str[L-next[L]-1] = str[L-next[L]-1+L-next[L]-1] = str[2*(L-next[L]-1)];
假设S = L-next[L]-1;则有str[0]=str[s]=str[2*s]=str[3*s]…str[k*s],对于所有i%s==0,均有s[i]=s[0]
同理,str[1]=str[s+1]=str[2*s+1]….
str[j]=str[s+j]=str[2*s+j]….
综上,若L%S==0,则可得L为str[0]…str[s-1]的相同字串组成,
总长度为L,其中字串长度SL = s-0+1=L-next[L],循环次数为L/SL
故对于所有大于1的前缀,只要其符合上述条件,即为答案之一
#include<iostream>
using namespace std;
const int Max = 1000005;
char str[Max];
int len, next[Max];
void get_next(){
int i = 0, j = -1;
next[0] = -1;
while(i < len){
if(j == -1 || str[i] == str[j]){
i ++; j ++;
next[i] = j;
}
else j = next[j];
}
}
int main(){
int i, testCase = 1;
while(scanf("%d", &len) && len){
scanf("%s", str);
get_next();
printf("Test case #%d\n", testCase ++);
for(i = 2; i <= len; i ++)
if(next[i] != 0 && i % (i-next[i]) == 0)
printf("%d %d\n", i, i / (i-next[i]));
printf("\n");
}
return 0;
}
自己用的是2406的len-next[len],也就是分为了两种情况,不知道为什么WA,可有有什么特殊数据?
附上自己WA的代码:
#include<iostream>
#include<cstring>
#include <cstdio>
#include <cstring>
using namespace std;
const int Max = 100000005;
char str[Max]; // 模式串。
int len, next[Max];
void get_next(){
int i = 0, j= -1;
next[0] =-1;
while(i< len){
if(j == -1 || str[i] == str[j]){
++i; ++j;
next[i] = j;
}
else j = next[j];
}
}
int main(){
while(scanf("%d", &len) != EOF&&len!=0){
scanf("%s",str);
int cases = 1;
int q=0;
int k1 = 0,k2 = 0,ans=0;
printf("Test case #%d\n",cases++);
for(int i = 0;i<len;i++){
if(str[1]==str[0]){
for(q = 0;q<len;q++){
if(str[q]!=str[0]){
k2=q;
break;
}
}
}
if(q!=len&&q!=0)
printf("%d %d\n",k2,k2);
break;
}
get_next();
k1= len-next[len];//k为子川的长度
ans = len / (len-next[len]);//ans为共有几个这个的子串
for(int i = 2;i<=ans;i++)
printf("%d %d\n",i*k1,i);
printf("\n");
}
return 0;
}