【POJ2752】Seek the Name, Seek the Fame-KMP思想
测试地址:Seek the Name, Seek the Fame
题目大意:多组测试数据,每组给定一个字符串S,要求求出既是S前缀又是S后缀的子串的所有可能长度。
做法:乍一看这题好像无从下手,但其实我们仔细观察这种性质,就可以发现这个过程和KMP中求next函数的过程是相似的,把S当成模式串来计算next函数,最后一个字符时特殊处理,用与计算next函数过程中寻找最大公共长度的循环相似的过程,可以看出可以取到的index的值表示除最后一个字符外的S串中,前index个字符和后index个字符是相同的,这时只要比对第index+1个字符和最后一个字符是否相等,如果相等,则index+1为一个可能的答案,与平常计算next函数的过程的唯一不同,就是验证相等后并不马上结束,而是寻找所有可能的情况,由于我们找到的答案呈降序排列,而题目要求输出升序,反过来输出即可,最后输出S串的长度即可(因为整个S串一定是它自己的前缀与后缀,并且这个值我们在前面没有能计算出来,所以需要额外输出)。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
char p[400010];
int overlay[400010],ans[400010],lenp;
void calc_overlay()
{
int index;
overlay[0]=0;
for(int i=1;i<lenp-1;i++)
{
index=overlay[i-1];
while(index>=1&&p[index]!=p[i])
{
index=overlay[index-1];
}
if (p[index]==p[i]) overlay[i]=index+1;
else overlay[i]=0;
}
}
int main()
{
while(scanf("%s",p)!=EOF)
{
lenp=strlen(p);
calc_overlay();
if (lenp==1) {printf("1\n");continue;}
else
{
int index;
ans[0]=0;
index=overlay[lenp-2];
while(index>=0)
{
if (p[index]==p[lenp-1]) ans[++ans[0]]=index+1;
if (index==0) break;
index=overlay[index-1];
}
for(int i=ans[0];i>=1;i--) printf("%d ",ans[i]);
printf("%d\n",lenp);
}
}
return 0;
}