#1449 : 后缀自动机三·重复旋律6
时间限制:15000ms
单点时限:3000ms
内存限制:512MB
描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为一段数构成的数列。
现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数。但是K不是固定的,小Hi想知道对于所有的K的答案。
输入
共一行,包含一个由小写字母构成的字符串S。字符串长度不超过 1000000。
输出
共Length(S)行,每行一个整数,表示答案。
样例输入
aab
样例输出
2 1 1
#include<stdio.h>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
#define LL long long
typedef struct Node
{
int len, pre; //pre:对应图片中的绿线(一个节点显然最多只有一条绿线)
int Next[26]; //Next[]:对应图片中的蓝线
}Node;
Node tre[2000005];
vector<int> G[2000005]; //
int cnt, last, siz[2000005], ans[2000005];
char str[1000005];
void Init()
{
cnt = last = 0;
memset(tre, 0, sizeof(tre));
tre[cnt++].pre = -1;
}
void Insert(char ch)
{
int p, q, now, rev;
p = last, now = cnt++;
tre[now].len = tre[last].len+1;
siz[now]++; //如果节点u包含子串S[1..i],那么满足|siz(u)| = ∑|siz(son(u))|+1,这里先加上那个1,这样的话对于SL树就可以直接求和了
while(p!=-1 && tre[p].Next[ch-'a']==0) //每次跳到当前最长且siz集合与当前不同的后缀上,对应图片中的绿线回退(例如7→8→5→S)
{
tre[p].Next[ch-'a'] = now; //tran(st[p], ch)=now,对应图片中的蓝线连接
p = tre[p].pre;
}
if(p==-1)
tre[now].pre = 0; //情况①,递归到了初始节点S(空子串)(例如图片中的9号节点pre[9]=0)
else //如果中途某个子串tran(st[p], ch)已经存在
{
q = tre[p].Next[ch-'a'];
if(tre[q].len==tre[p].len+1) //情况②:节点q的最长子串刚好就是节点p的最长子串+S[i],也就是len[q] = len[p]+1
tre[now].pre = q;
else //情况③
{
rev = cnt++;
tre[rev] = tre[q];
tre[rev].len = tre[p].len+1; //这三行就是对Suffix Links内向树的插点操作
tre[q].pre = tre[now].pre = rev;
while(p!=-1 && tre[p].Next[ch-'a']==q)
{
tre[p].Next[ch-'a'] = rev;
p = tre[p].pre;
}
}
}
last = now;
}
void SechSL(int u) //求出所有节点的|endpos()|
{
int i, v;
for(i=0;i<G[u].size();i++)
{
v = G[u][i];
SechSL(v);
siz[u] += siz[v];
}
ans[tre[u].len] = max(ans[tre[u].len], siz[u]);
}
int main(void)
{
int n, i;
scanf("%s", str+1);
n = strlen(str+1);
Init();
for(i=1;i<=n;i++)
Insert(str[i]);
for(i=1;i<=cnt-1;i++) //建树
G[tre[i].pre].push_back(i);
SechSL(0);
/*---------------------------
LL ans = 0;
for(i=1;i<=cnt-1;i++)
ans += tre[i].len-tre[tre[i].pre].len; //求出有多少个本质不同的子串
-----------------------------*/
for(i=n;i>=1;i--)
ans[i] = max(ans[i], ans[i+1]);
for(i=1;i<=n;i++)
printf("%d\n", ans[i]);
return 0;
}