给定一个字符串,要求找到同时是它前缀也是后缀的字符串的个数,并且输出他们的长度。
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 }