-
总时间限制:
- 3000ms 内存限制:
- 65536kB
-
描述
-
一个字符串的前缀是从第一个字符开始的连续若干个字符,例如"a
baab"共有5个前缀,分别是a, ab, aba, abaa, abaab。
我们希望知道一个N位字符串S的前缀是否具有循环节。换言之,对于每一个从头开始的长度为 i (i 大于1)的前缀,是否由重复出现的子串A组成,即 AAA...A (A重复出现K次,K 大于 1)。如果存在,请找出最短的循环节对应的K值( 也就是这个前缀串的所有可能重复节中,最大的K值)。
输入
-
输入包括多组测试数据。每组测试数据包括两行。
第一行包括字符串S的长度N(2 <= N <= 1 000 000)。
第二行包括字符串S。
输入数据以只包括一个0的行作为结尾。
输出
-
对于每组测试数据,第一行输出 "Test case #“ 和测试数据的编号。
接下来的每一行,输出前缀长度i和重复测数K,中间用一个空格隔开。前缀长度需要升序排列。
在每组测试数据的最后输出一个空行。样例输入
3 aaa 12 aabaabaabaab 0
样例输出Test case #1 2 2 3 3 Test case #2 2 2 6 2 9 3 12 4
这题考得是,KMP的性质。。
这题曾差点让我不想再学MOOC 的数据结构与算法,因为谷歌百度以后都有答案 但是就是看不出。。。
推荐好去处。
http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html
曾近有那么点理解。很久没用。现在完全不懂代码。
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; char s[1000100]; int next[1000100]; int t=1; int main() { int N; while(scanf("%d",&N)!=EOF&&N!=0) { cin>>s; int i; memset(next,0,sizeof(next)); next[0] = 0; for(i=1; i<N; i++) { int j = next[i-1];// j 表示当前匹配了多少位 while(j&&s[j]!=s[i]) j = next[j-1]; if(s[i]==s[j]) next[i]=j+1; else next[i] = 0; } cout<<"Test case #"<<t++<<endl; for(i=2 ; i<=N; i++) { if(i%(i-next[i-1])==0&&i/(i-next[i-1])>1) cout<<i<<" "<<i/(i-next[i-1])<<endl; } cout<<endl; } return 0; }