HihoCoder1445 重复旋律5(后缀自动机)
2017-11-22 18:16
441 查看
重复旋律5
时间限制:10000ms单点时限:2000ms
内存限制:512MB
描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为一段数构成的数列。现在小Hi想知道一部作品中出现了多少不同的旋律?
输入
共一行,包含一个由小写字母构成的字符串。字符串长度不超过 1000000。输出
一行一个整数,表示答案。样例输入
aab
样例输出
5
2017-11-22:从代码看,是比ac自动机优美,但是ac自动机是基础在kmp和字典树上面,学习起来很快,然而后缀自动机就灰常难以YY啦。
目前感觉似懂非懂,等把后面几个题AC了再回来整理吧。
2017-11-25:三天,做了几个题之后,基本上是弄懂了。感觉后缀自动机很强大,打算再花一周来练习。
#include<iostream> #include<cstring> #include<cstdio> #include<cstring> #include<algorithm> #include<string> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int N=1000010; int tot=1,n,slink[2*N],trans[2*N][26],minlen[2*N],maxlen[2*N]; char str ; ll ans=0; 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]; else for(int i=0;i<26;i++) trans[tot][i]=-1; return tot; } int add_char(char ch,int u) { int c=ch-'a',v=u; int z=newstate(maxlen[u]+1,-1,NULL,0); while(v!=-1&&trans[v][c]==-1) { trans[v][c]=z; v=slink[v]; } if(v==-1) { minlen[z]=1; slink[z]=0; return z; } int x=trans[v][c]; if(maxlen[v]+1==maxlen[x]) { slink[z]=x; minlen[z]=maxlen[x]+1; return z; } int y=newstate(maxlen[v]+1,-1,trans[x],slink[x]); slink[z]=slink[x]=y; minlen[x]=minlen[z]=maxlen[y]+1; while(v!=-1&&trans[v][c]==x) { trans[v][c]=y; v=slink[v]; } minlen[y]=maxlen[slink[y]]+1; return z; } int main() { scanf("%s",str); int len=strlen(str),pre=0; memset(trans[0],-1,sizeof(trans[0])); slink[0]=-1; for(int i=0; i<len; i++) { pre=add_char(str[i],pre); } for(int i=2; i<=tot; i++) { ans+=maxlen[i]-minlen[i]+1; } printf("%lld\n",ans); return 0; }
做了HDU4641再回来改动一下,minlen[i]=maxlen[slink[i]],所以没必要保存minlen了。代码稍微简短了一点:
#include<iostream> #include<cstring> #include<cstdio> #include<cstring> #include<algorithm> #include<string> using namespace std; const int maxn=1000100; int tot,slink[2*maxn],trans[2*maxn][26],maxlen[2*maxn]; char str[2*maxn]; int N,M,K,num[2*maxn],last; long long ans; void init() { ans=tot=0; last=0; memset(trans[0],-1,sizeof(trans[0])); slink[0]=-1; maxlen[0]=0; } void add_char(char chr) { int c=chr-'a'; int p=last,np=++tot; maxlen[np]=maxlen[p]+1; memset(trans[np],-1,sizeof(trans[np])); num[np]=0; while(p!=-1&&trans[p][c]==-1) trans[p][c]=np,p=slink[p]; if(p==-1) slink[np]=0; else { int q=trans[p][c]; if(maxlen[q]!=maxlen[p]+1) { int nq=++tot; memcpy(trans[nq],trans[q],sizeof(trans[q])); num[nq]=num[q]; maxlen[nq]=maxlen[p]+1; slink[nq]=slink[q]; slink[np]=slink[q]=nq; while(p!=-1&&trans[p][c]==q) trans[p][c]=nq,p=slink[p]; } else slink[np]=q; } last=np; } int main() { init(); scanf("%s",str); N=strlen(str); for(int i=0; i<N; i++) add_char(str[i]); for(int i=1;i<=tot;i++) ans+=maxlen[i]-maxlen[slink[i]]; printf("%lld\n",ans); return 0; }
相关文章推荐
- 【hihocoder1445】后缀自动机二·重复旋律5 后缀自动机模板
- hihocoder 1445 : 后缀自动机二·重复旋律5(后缀自动机)
- HihoCoder - 1445 后缀自动机二·重复旋律5 后缀自动机
- 【后缀自动机】hihocoder1445 后缀自动机二·重复旋律5
- [SAM] hihoCoder1445 后缀自动机二·重复旋律5
- hihoCoder #1445 : 后缀自动机二·重复旋律5
- hihoCoder 后缀自动机三·重复旋律6
- 【后缀自动机】hihocoder1449 后缀自动机三·重复旋律6
- 【后缀自动机】【拓扑排序】【动态规划】hihocoder1457 后缀自动机四·重复旋律7
- 【hihocoder1457】后缀自动机四·重复旋律7 后缀自动机
- HihoCoder1465 重复旋律8(后缀自动机)
- hihocoder #1445 : 后缀自动机二·重复旋律5
- 【hihoCoder 1466】后缀自动机六·重复旋律9
- HihoCoder - 1449 后缀自动机三·重复旋律6 后缀自动机、递推、DFS
- hihocoder #1445 : 后缀自动机二·重复旋律5
- HihoCoder1449 重复旋律6(后缀自动机)
- hihoCoder.1457.后缀自动机四 重复旋律7(广义后缀自动机)
- HihoCoder - 1457 后缀自动机四·重复旋律7 后缀自动机+拓扑排序+递推、BFS
- hihoCoder.1465.后缀自动机五 重复旋律8(后缀自动机)
- HihoCoder1403 后缀数组一·重复旋律1