P
O
J
2752
S
e
e
k
t
h
e
N
a
m
e
,
S
e
e
k
t
h
e
F
a
m
e
POJ2752\ Seek\ the\ Name, Seek\ the\ Fame
POJ2752 Seek the Name,Seek the Fame
【简要题意】
给定一个字符串,从小到大输出
s
s
s中既是前缀又是后缀的子串长度
【题解】
K
M
P
KMP
KMP比较裸的题,考察对
K
M
P
KMP
KMP里
n
x
t
nxt
nxt数组的理解
借用
K
M
P
KMP
KMP算法的
n
e
x
t
next
next数组,设s的长度为
n
n
n,则
s
s
s串本身必定满足条件。其他满足条件的子串特征:该子串的最后一个字符肯定与
s
s
s的最后一个字符相同。这正是
n
e
x
t
next
next数组发挥作用的时候。从
n
−
1
n - 1
n−1位既最后一位开始回滚,若
s
[
n
e
x
t
[
n
−
1
]
]
=
=
s
[
n
−
1
]
s[next[n-1]] == s[n-1]
s[next[n−1]]==s[n−1],则子串
s
[
0
,
1
,
2
,
.
.
.
,
n
e
x
t
[
n
−
1
]
]
s[0,1,2,...,next[n-1]]
s[0,1,2,...,next[n−1]]是满足条件的子串。然后判断
s
[
n
e
x
t
[
n
e
x
t
[
n
−
1
]
]
]
=
=
s
[
n
−
1
]
s[next[next[n-1]]] == s[n-1]
s[next[next[n−1]]]==s[n−1]是否成立,这样一直回滚,直到
n
e
x
t
[
n
e
x
t
[
.
.
.
.
.
n
e
x
t
[
n
−
1
]
]
]
=
=
0
next[next[.....next[n-1]]] == 0
next[next[.....next[n−1]]]==0(即已经匹配到第一位)为止。把答案从大到小存下来,再从小到大输出即可。
多组数据注意清空
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
const int N=400000+50;
int kmp[N],j,ans[N];
char b[N];
inline int read(){
int cnt=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
while(isdigit(c)){cnt=(cnt<<1)+(cnt<<3)+(c^48);c=getchar();}
return cnt*f;
}
signed main(){
while (scanf("%s", b+1)!=EOF){
memset(kmp,0,sizeof(kmp));
j=0;
int lb=strlen(b+1);
for (int i=2;i<=lb;i++){
while(j&&b[i]!=b[j+1])
j=kmp[j];
if(b[j+1]==b[i])j++;
kmp[i]=j;
}
int cnt=0;
int t=kmp[lb];
while(t!=0){
if(b[t]==b[lb])ans[++cnt]=t;
t=kmp[t];
}
for(int i=cnt;i>=1;--i){printf("%d ",ans[i]);}
printf("%d\n",lb);
}
return 0;
}