NSUBSTR - Substrings
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 500003
using 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]);
}