Live2d Test Env

HihoCoder1449 重复旋律6(后缀自动机)

描述

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

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

输入

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

输出

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

样例输入

aab

样例输出

2
1
1

1,很好的利用了拓扑。

2,利用了单调性。

  for(i=tot;i>0;i--){
        ans[i]=max(ans[i],ans[i+1]);
    }

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+100;
const int M=1e6+5;
int tot,slink[2*N],trans[2*N][26],minlen[2*N],maxlen[2*N],edpts[2*N],n;
char str[2*N];
int blue[2*N],ind[2*N],ans[2*N+10];
int newstate(int _maxlen,int _minlen,int* _trans,int _slink) {
    maxlen[++tot]=_maxlen;
    minlen[tot]=_minlen;
    slink[tot]=_slink;
    if(_trans)
        for(int i=0; i<26; 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]+1,-1,NULL,0);
    blue[z]=1;//绿色 
    while(v&&!trans[v][c]) {
        trans[v][c]=z;
        v=slink[v];
    }
    if(!v) {
        minlen[z]=1;
        slink[z]=1;
        ind[0]++;
        return z;
    }
    int x=trans[v][c];
    if(maxlen[v]+1==maxlen[x]) {
        slink[z]=x;
        minlen[z]=maxlen[x]+1;
        ind[x]++;
        return z;
    }
    int y=newstate(maxlen[v]+1,-1,trans[x],slink[x]);
    slink[z]=slink[x]=y;
    ind[y]+=2;
    minlen[x]=minlen[z]=maxlen[y]+1;
    while(v&&trans[v][c]==x) {
        trans[v][c]=y;
        v=slink[v];
    }
    minlen[y]=maxlen[slink[y]]+1;
    return z;
}
void count() {
    queue<int> q;
    for( int i=1; 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=1;
    tot=1;
    for(i=0; i<len; i++) {
        pre=add(str[i],pre);
    }
    count();
    for(i=0;i<=tot;i++){
        ans[maxlen[i]] = max(ans[maxlen[i]],edpts[i]);
    }
    for(i=tot;i>0;i--){
        ans[i]=max(ans[i],ans[i+1]);
    }
    for(i=1;i<=len;i++)printf("%d\n",ans[i]);
    return 0;
}

 

posted @ 2017-11-24 11:17  nimphy  阅读(377)  评论(0编辑  收藏  举报