hihocoder #1449 : 后缀自动机三·重复旋律6

 

#1449 : 后缀自动机三·重复旋律6

时间限制:15000ms
单点时限:3000ms
内存限制:512MB

描述

小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为一段数构成的数列。

现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数。但是K不是固定的,小Hi想知道对于所有的K的答案。

解题方法提示

输入

共一行,包含一个由小写字母构成的字符串S。字符串长度不超过 1000000。

输出

共Length(S)行,每行一个整数,表示答案。

样例输入
aab
样例输出
2
1
1

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;

const int maxn=2000000+5;

int last=1,tail=1,ans[maxn],cnt[maxn],out[maxn],Min[maxn],Max[maxn],nxt[maxn][26],fail[maxn];

char s[maxn];

inline void build(char *s){
	while(*s){
		int p=last,t=++tail,c=*s++-'a';
		Max[t]=Max[p]+1;cnt[t]=1;
		while(p&&!nxt[p][c])
			nxt[p][c]=t,p=fail[p];
		if(p){
			int q=nxt[p][c];
			if(Max[q]==Max[p]+1)
				fail[t]=q,Min[t]=Max[q]+1;
			else{
				int k=++tail;
				fail[k]=fail[q];
				fail[t]=fail[q]=k;
				Max[k]=Max[p]+1;
				Min[q]=Max[k]+1;
				Min[t]=Max[k]+1;
				Min[k]=Max[fail[k]]+1;
				memcpy(nxt[k],nxt[q],26*sizeof(int));
				while(p&&nxt[p][c]==q)
					nxt[p][c]=k,p=fail[p];
			}
		}
		else
			fail[t]=Min[t]=1;
		last=t;
	}
}

inline void calc(void){
	for(int i=1;i<=tail;i++)
		out[fail[i]]++;
	int hd=1,ta=0,len=strlen(s),q[maxn];
	for(int i=1;i<=tail;i++)
		if(!out[i]) q[++ta]=i;
	while(hd<=ta){
		int top=q[hd++];
		cnt[fail[top]]+=cnt[top];
		out[fail[top]]--;
		if(!out[fail[top]])
			q[++ta]=fail[top];
	}
	for(int i=1;i<=tail;i++)
		ans[Max[i]]=max(ans[Max[i]],cnt[i]);
	for(int i=len-1;i>=1;i--)
		ans[i]=max(ans[i+1],ans[i]);
	for(int i=1;i<=len;i++)
		printf("%d\n",ans[i]);
}

signed main(void){
	scanf("%s",s);build(s);calc();
	return 0;
}

  


$By$  $NeighThorn$

posted @ 2017-04-20 09:01  NeighThorn  阅读(246)  评论(0编辑  收藏  举报