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; }
It is your time to fight!