描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为一段数构成的数列。
现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数。但是K不是固定的,小Hi想知道对于所有的K的答案。
输入
共一行,包含一个由小写字母构成的字符串S。字符串长度不超过 1000000。
输出
共Length(S)行,每行一个整数,表示答案。
样例输入
aab
样例输出
2
1
1
1,很好的利用了拓扑。
2,利用了单调性。
for(i=tot;i>;i--){
ans[i]=max(ans[i],ans[i+]);
}
2017-11-24 代码是舶来品,参考hihocoder,等把后缀自动机消化了自己再写一遍吧。
2017-11-25 这几个题理解得差不多了。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
#include<queue>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=1e6+;
const int M=1e6+;
int tot,slink[*N],trans[*N][],minlen[*N],maxlen[*N],edpts[*N],n;
char str[*N];
int blue[*N],ind[*N],ans[*N+];
int newstate(int _maxlen,int _minlen,int* _trans,int _slink) {
maxlen[++tot]=_maxlen;
minlen[tot]=_minlen;
slink[tot]=_slink;
if(_trans)
for(int i=; i<; i++)
trans[tot][i]=_trans[i];
return tot;
}
int add(char ch,int u) {
int c=ch-'a',v=u;
int z=newstate(maxlen[u]+,-,NULL,);
blue[z]=;//绿色
while(v&&!trans[v][c]) {
trans[v][c]=z;
v=slink[v];
}
if(!v) {
minlen[z]=;
slink[z]=;
ind[]++;
return z;
}
int x=trans[v][c];
if(maxlen[v]+==maxlen[x]) {
slink[z]=x;
minlen[z]=maxlen[x]+;
ind[x]++;
return z;
}
int y=newstate(maxlen[v]+,-,trans[x],slink[x]);
slink[z]=slink[x]=y;
ind[y]+=;
minlen[x]=minlen[z]=maxlen[y]+;
while(v&&trans[v][c]==x) {
trans[v][c]=y;
v=slink[v];
}
minlen[y]=maxlen[slink[y]]+;
return z;
}
void count() {
queue<int> q;
for( int i=; i <=tot; i++ )if( !ind[i] ) {
q.push(i);
}
while( !q.empty() ) {
int u = q.front();
q.pop();
if(blue[u] ) edpts[u]++;
edpts[ slink[u]] += edpts[u];
if( !--ind[slink[u]] ) q.push(slink[u]);
}
} int main() {
int i;
scanf("%s",str);
int len=strlen(str),pre=;
tot=;
for(i=; i<len; i++) {
pre=add(str[i],pre);
}
count();
for(i=;i<=tot;i++){
ans[maxlen[i]] = max(ans[maxlen[i]],edpts[i]);
}
for(i=tot;i>;i--){
ans[i]=max(ans[i],ans[i+]);
}
for(i=;i<=len;i++)printf("%d\n",ans[i]);
return ;
}