转载自FreeCode#的博客
题意:将子序列中有周期性前缀的输出并输出其出现的次数
KMP算法。
这道题考察的是KMP算法中next数组的应用,必须理解透next[]数组代表的含义才能通过它解决这道题。
思路是先构造出 next[] 数组,下标为 i,定义一个变量 j = i - next[i] 就是next数组下标和下标对应值的差,如果这个差能整除下标 i,即 i%j==0 ,则说明下标i之前的字符串(周期性字符串长度为 i)一定可以由一个前缀周期性的表示出来,这个前缀的长度为刚才求得的那个差,即 j,则这个前缀出现的次数为 i/j 。所以最后输出i和i/j即可。
举这道题的第二组输入样例为例:
其next[]数组为:
i 0 1 2 3 4 5 6 7 8 9 10 11
a[i] a a b a a b a a b a a b
next[i] -1 0 1 0 1 2 3 4 5 6 7 8
next[i]值是0或-1的忽略。
注意:由于输出次数太多 (2 <= N <= 1 000 000),建议用printf输出,否则会超时。
代码:
#include <iostream>
#include <stdio.h>
using namespace std;
char a[1000010];
int next[1000010];
int n;
void GetNext() //获得a数列的next数组
{
int i=0,k=-1;
next[0] = -1;
while(i<n){
if(k==-1){
next[i+1] = 0;
i++;k++;
}
else if(a[i]==a[k]){
next[i+1] = k+1;
i++;k++;
}
else
k = next[k];
}
}
void DisRes(int num)
{
int j;
printf("Test case #%d\n",num);
for(int i=0;i<=n;i++){
if(next[i]==-1 || next[i]==0) //next[i]是-1或0的忽略,说明之前没有周期性前缀
continue;
j = i - next[i];
if(i%j==0) //能整除,说明存在周期性前缀
printf("%d %d\n",i,i/j); //输出这个前缀的长度和周期数
}
printf("\n");
}
int main()
{
int num = 0;
while(scanf("%d",&n)!=EOF){
if(n==0) break;
scanf("%s",a);
GetNext(); //获得next[]数组
DisRes(++num); //输出结果
}
return 0;
}