题目1 : 后缀自动机三·重复旋律6
时间限制:15000ms
单点时限:3000ms
内存限制:512MB
描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为一段数构成的数列。
现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数。但是K不是固定的,小Hi想知道对于所有的K的答案。
解题方法提示
输入
共一行,包含一个由小写字母构成的字符串S。字符串长度不超过 1000000。
输出
共Length(S)行,每行一个整数,表示答案。
样例输入
aab
样例输出
2
1
1
#include <bits/stdc++.h>
using namespace std;
const int mxn = 2000005;
namespace suffixAutomaton
{
int tail=2;
int fail[mxn];
int maxi[mxn];
int mini[mxn];
int size[mxn];
int next[mxn][26];
inline int extend(int p,int c)
{
int t=tail++;
size[t]=1;
maxi[t]=maxi[p]+1;
while(p&&!next[p][c])
next[p][c]=t,p=fail[p];
if(p)
{
int q=next[p][c];
if(maxi[q]==maxi[p]+1)
fail[t]=q,mini[t]=maxi[q]+1;
else
{
int k=tail++;
fail[k]=fail[q];
fail[q]=fail[t]=k;
maxi[k]=maxi[p]+1;
mini[q]=maxi[k]+1;
mini[t]=maxi[k]+1;
mini[k]=maxi[fail[k]]+1;
for(int i=0;i<26;i++)
next[k][i]=next[q][i];
while(p&&next[p][c]==q)
next[p][c]=k,p=fail[p];
}
}
else fail[t]=1,mini[t]=1;
return t;
}
int que[mxn];
int cnt[mxn];
inline void getSize()
{
int l=0,r=0;
for(int i=2;i<tail;i++)
++cnt[fail[i]];
for(int i=2;i<tail;i++)
if(!cnt[i]) que[r++]=i;
while(l!=r)
{
int u=que[l++],v=fail[u];
size[v]+=size[u];
if(!--cnt[v])
que[r++]=v;
}
}
}
using namespace suffixAutomaton;
int n,f[mxn];
char s[mxn];
int main()
{
scanf("%s",s);
n=strlen(s);
int last=1;
for(int i=0;i<n;i++)
last=extend(last,s[i]-'a');
getSize();
for(int i=2;i<tail;i++)
f[maxi[i]]=max(f[maxi[i]],size[i]);//不同的集合的最长的子串长度有可能相同
for(int i=n;i>=1;i--)
f[i]=max(f[i],f[i+1]);//长的子串必定包含更短的子串
for(int i=1;i<=n;i++)
printf("%d\n",f[i] );
}