For each prefix with length P of a given string S,if
Input
S[i]=S[i+P] for i in [0..SIZE(S)-p-1],
then the prefix is a “period” of S. We want to all the periodic prefixs.
Input contains multiple cases.
Output
The first line contains an integer T representing the number of cases. Then following T cases.
Each test case contains a string S (1 <= SIZE(S) <= 1000000),represents the title.S consists of lowercase ,uppercase letter.
For each test case, first output one line containing "Case #x: y", where x is the case number (starting from 1) and y is the number of periodic prefixs.Then output the lengths of the periodic prefixs in ascending order.
Sample Input
4 ooo acmacmacmacmacma fzufzufzuf stostootsstoSample Output
Case #1: 3 1 2 3 Case #2: 6 3 6 9 12 15 16 Case #3: 4 3 6 9 10 Case #4: 2 9 12
题意:输出所有可能的循环节。
思路:对next数组的理解。
反思:一开始的想法是找出最小循环节len-next[len].然后用最小循环节来找所有可能的循环节。后来一直wa。用随机法打了一些表找到了一组能证明错误的数据ababaaaabab.用最小循环节来求答案是7,11,正确答案是7,9,11。
最小循环节不能代表所有循环节。
AC代码:
#include<stdio.h> #include<string.h> #include<algorithm> #include<queue> #define M 1000010 using namespace std; int nextt[M],len; char a[M]; void init_kmp() { int i=0,j=-1; nextt[0]=-1; len=strlen(a); while(i<len) { if(j==-1||a[i]==a[j]) { nextt[++i]=++j; } else j=nextt[j]; } } queue<int>q; int main() { int t,ph=1; scanf("%d",&t); while(t--) { scanf("%s",a); init_kmp(); int j=len; while(j>0) { j=nextt[j]; q.push(j); } printf("Case #%d: %d\n",ph++,q.size()); printf("%d",len-q.front());//输出格式 q.pop(); while(!q.empty()) { printf(" %d",len-q.front()); q.pop(); }printf("\n"); } }错误思路代码(留下参考,不再犯):
#include<stdio.h> #include<string.h> #include<algorithm> #define M 1000010 using namespace std; char a[M]; int nextt[M],len; void KMP() { int i=0,j=-1; nextt[0]=-1; len=strlen(a); while(i<len) { if(j==-1||a[i]==a[j]) { nextt[++i]=++j; } else j=nextt[j]; } } int main() { int n,ph=1; scanf("%d",&n); while(n--) { scanf("%s",a); KMP(); int tt=len-nextt[len]; printf("Case #%d: %d\n",ph++,(len+tt-1)/tt); int i=tt; for(;i<len;i+=tt) { printf("%d ",i); } printf("%d \n",len); } }