SPOJ 8222 NSUBSTR - Substrings (后缀自动机)

来源:互联网 发布:虚幻4 编程语言 编辑:程序博客网 时间:2024/06/10 10:51

NSUBSTR - Substrings

no tags 

You are given a string S which consists of 250000 lowercase latin letters at most. We define F(x) as the maximal number of times that some string with length x appears in S. For example for string 'ababa' F(3) will be 2 because there is a string 'aba' that occurs twice. Your task is to output F(i) for every i so that 1<=i<=|S|.

Input

String S consists of at most 250000 lowercase latin letters.

Output

Output |S| lines. On the i-th line output F(i).

Example

Input:
ababa

Output:
3
2
2
1
1

题目大意:f(i)表示的是长度为i的子串的最大出现次数,求f(1..n).

题解:后缀自动机

S的一个子串str,right(str)表示str在s中每次出现位置的右端点组成的集合。

fa表示一个状态s的父状态,right(s)属于right(fa)

每个状态s表示的串的长度是区间(len(fa),len(s)]

每个状态s表示的串在原串中的出现次数及出现的右端点相同。

right的求法,按照parent树中深度从大到小,依次将每个状态的right集合并入他fa状态的right集合。

我们用每个状态的|right|去更新f(len(s)),然后用f(i)去更新f(i-1)

在主链上的每个节点表示的是原串的一个前缀,出现的次数应该是+1

如果一个节点+1,那么对应的他的fa链上的节点都要+1。

#include<iostream>#include<cstring>#include<algorithm>#include<cstdio>#include<cmath>#define N 500003using namespace std;int n,m;int ch[N][30],fa[N],l[N],last,a[N];int cnt,p,q,np,nq,root,rt[N],b[N],t[N],f[N];char s[N];void extend(int x){int c=a[x];p=last; np=++cnt; last=np;l[np]=x;for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;if (!p) fa[np]=root;else {int q=ch[p][c];if (l[p]+1==l[q]) fa[np]=q;else {nq=++cnt; l[nq]=l[p]+1;memcpy(ch[nq],ch[q],sizeof ch[nq]);fa[nq]=fa[q];fa[q]=fa[np]=nq;for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;}}}int main(){scanf("%s",s+1); n=strlen(s+1);last=root=++cnt;for (int i=1;i<=n;i++) a[i]=s[i]-'a';for (int i=1;i<=n;i++) extend(i);p=root;for (int i=1;i<=n;i++) p=ch[p][a[i]],rt[p]++;for (int i=1;i<=cnt;i++) b[l[i]]++;//for (int i=1;i<=cnt;i++) cout<<l[i]<<" ";//cout<<endl;for (int i=1;i<=n;i++) b[i]+=b[i-1];for (int i=1;i<=cnt;i++) t[b[l[i]]--]=i;for (int i=cnt;i;i--) rt[fa[t[i]]]+=rt[t[i]];//for (int i=cnt;i;i--) cout<<rt[i]<<" ";//cout<<endl;for (int i=1;i<=cnt;i++) f[l[i]]=max(f[l[i]],rt[i]);for (int i=n-1;i;i--) f[i]=max(f[i],f[i+1]);for (int i=1;i<=n;i++) printf("%d\n",f[i]);}


0 0
原创粉丝点击