Stringland有一只小猫非常有名,许多夫妇跋涉到Stringland请小猫为他们的新出生的婴儿起名字,他们寻求这个名字,同时寻求名声。为了摆脱这种无聊的工作,创新的小猫制定了一个简单而奇妙的算法:
第一步、将父亲的姓名和母亲的姓名连接到一个新的字符串S.
第二步、找一个 S 的前缀-后缀串作为新生儿的名字(前缀-后缀串是S的前缀,又是S的后缀)
比如:父亲='ala',母亲='la',我们有S ='ala'+'la'='alala'。S的潜在前缀-后缀字符串是{'a','ala','alala'}。给定字符串S,你能帮助小猫编写一个程序来计算S的可能前缀-后缀字符串的长度吗?(他可能会给你的宝宝起一个名字来感谢你:)
Input
输入包含多组数据。每个测试用例包含一行字符串 S 。
S 只包含小写字母, 1<= |S| <=400000 。
Output
对于每个测试用例,按递增顺序输出一行整数,表示新宝宝名称的可能长度。
Sample Input
ababcababababcabab
aaaaa
alala
nucacm
Sample Output
2 4 9 18
1 2 3 4 5
1 3 5
6
题意是从一个字符串中找出一个子串(这个字符串也是一个子串,这个字符串既前缀,又是后缀,所以相同),要求前后缀相同的,我们要记录输出那个子串的位置,并且从小到大输出答案。
在这里我们用到了KMP next 数组,我们都已经知道了,这个next 数组就是保存 当前位置前面包括这个字符 所组成的字符串 相同前后缀最大数量,利用这个我们从最后一位的前面逐渐找前后缀相同的,然后再与这个大字符串最后一位比较,如果相同的话,就是一个答案,我们就可以利用这个性质,我们得从后往前找这个答案,我们还要判断最后的一个字符与前面的那个子串最后一位是否相同,如果相同,答案是合理的。 其实这个做法就是从后往前找,先去掉一位最后的那个字符,找出最大相同前后缀然后再与最后那一位比较,如果行的话,就是一个答案,如果不行,那就不是答案。
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<vector>
#include<string.h>
const int maxn=400005;
using namespace std;
int nex[maxn];
char s[maxn];
int len;
void getnex(char t[])
{
int i=0;
int j=-1;
nex[0]=-1;
while(i<len)
{
if(j==-1||t[i]==t[j])
{
i++;
j++;
nex[i]=j;
}
else
j=nex[j];
}
for(int i=1;i<=len;i++)
cout<<nex[i]<<' ';
cout<<endl;
}
int main()
{
while(scanf("%s",s)!=EOF)
{
vector<int>ans;
len=strlen(s);
getnex(s);
int t=nex[len-1];
while(t!=-1)
{
if(s[t]==s[len-1])
ans.push_back(t+1);
t=nex[t];
}
ans.push_back(len);
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++)
cout<<ans[i]<<' ';
cout<<endl;
}
return 0;
}