Seek the Name, Seek the Fame

给定一个字符串,要求找到同时是它前缀也是后缀的字符串的个数,并且输出他们的长度。
Input
第一行一个数字N,第二行输入一个字符串,长度<= 10^6.
Output
输出这些子串的结束位置(因为它们的开始位置都是从1开始的),注意每个数字后面有一个空格.

Sample Input
5
aaaaa
Sample Output
1 2 3 4 5

题目大意:找出串中既是前缀又是后缀的所有子串,输出这些子串的结束位置。

如输入:

12

abcabcabcabc

输出:3 6 9 12

sol:先求出所有next[i]的值,将next[i]--i建立一条边,构造fail树,本题是要求整个字串的前缀和后缀的个数,不难发现,每个结点都是字符串的一个前缀,根据next的定义,我们又可以得出fail树中每条链上父亲点是儿子点的后缀,所以我们跟着fail树的结点n——next(n)——...——0,这条链链找上去,就会找到我们想要的答案。

上例next[12]=9,next[9]=6,next[6]=3,next[3]=0。这条链为:0——3(abc)——6(abcabc)——9(abcabcabc)——12(abcabcabcabc)。即前3,6,9,12位分别是该串前缀和后缀的长度。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 #define maxn 1000010
 6 using namespace std;
 7 char s[maxn];
 8 int n,pre[maxn],list[maxn];
 9 int main(){
10     scanf("%d",&n);
11     scanf("%s",s+1);
12     for (int i=2,j=0;i<=n;i++){
13         while (j&&s[j+1]!=s[i]) j=pre[j];
14         if (s[j+1]==s[i]) j++;
15         pre[i]=j;  
16     }
17     for (int i=n;i;i=pre[i])//从n开始倒着记录答案 
18        list[++list[0]]=i;
19     for (int i=list[0];i>=1;i--) printf("%d ",list[i]);//正着输出 
20     printf("
");
21     return 0;  
22 }
原文地址:https://www.cnblogs.com/cutepota/p/12535197.html