HihoCoder1449 后缀自动机三·重复旋律6
描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为一段数构成的数列。
现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数。但是K不是固定的,小Hi想知道对于所有的K的答案。
输入
共一行,包含一个由小写字母构成的字符串S。字符串长度不超过 1000000。
输出
共Length(S)行,每行一个整数,表示答案。
题解:
对S建立一个后缀自动机,我们可以先求出每个状态在原串中出现的次数cnt。对于复制的结点令cnt=0,转移的结点cnt=1,因为转移结点的状态保证至少有一个字符串,然后我们应该将一个状态的cnt值添加到它后缀链接的状态上,因为明显转移的状态的字符串被包含在原状态字符串中,所以我们可以用拓扑排序来更新状态的cnt值。
我们最后要求的是不同长度的字符串中出现次数的最大值,假设为ans[i],i从len(s)到1,ans肯定是非递减的,因为当前状态的字符串长于下一个状态的字符串,这意味着当前状态的字符串包含一个与下一个状态字符串等长的后缀。
所以有ans[i] = max(ans[i],ans[i+1]),ans的初始化为ans[st[i].len] = max(ans[st[i].len],st[i].cnt);
参考代码:

#include<bits/stdc++.h> using namespace std; #define PI acos(-1.0) #define mkp make_pair #define pii pair<int,int> #define fi first #define se second #define pb push_back typedef long long ll; const int INF=0x3f3f3f3f; const int maxn=1e6+10; char s[maxn]; struct SAM{ int fa[maxn<<1],l[maxn<<1],nxt[maxn<<1][26],last,cnt; int ans[maxn],num[maxn<<1],c[maxn<<1],rk[maxn<<1]; void Init() { memset(nxt[1],0,sizeof(nxt[1])); memset(num,0,sizeof(num)); memset(ans,0,sizeof(ans)); memset(c,0,sizeof(c)); memset(rk,0,sizeof(rk)); last=cnt=1; fa[1]=0;l[1]=0; } int NewNode() { ++cnt; memset(nxt[cnt],0,sizeof(nxt[cnt])); fa[cnt]=l[cnt]=0; return cnt; } void Add(int c) { int p=last,np=NewNode();num[np]=1; last=np;l[np]=l[p]+1; while(p&&!nxt[p][c]) nxt[p][c]=np,p=fa[p]; if(!p) fa[np]=1; else { int q=nxt[p][c]; if(l[q]==l[p]+1) fa[np]=q; else { int nq=NewNode(); memcpy(nxt[nq],nxt[q],sizeof(nxt[q])); fa[nq]=fa[q]; l[nq]=l[p]+1; fa[q]=fa[np]=nq; while(nxt[p][c]==q) nxt[p][c]=nq,p=fa[p]; } } } void topsort() { for(int i=1;i<=cnt;i++) c[l[i]]++; for(int i=1;i<=cnt;i++) c[i]+=c[i-1]; for(int i=1;i<=cnt;i++) rk[c[l[i]]--]=i; for(int i=cnt;i>=1;i--) { int x=rk[i]; num[fa[x]]+=num[x]; ans[l[x]] = max(ans[l[x]],num[x]); } for(int i=1,len=strlen(s+1);i<=len;i++) printf("%d\n",ans[i]); } } sam; int main() { scanf("%s",s+1); sam.Init(); int len=strlen(s+1); for(int i=1;i<=len;++i) sam.Add(s[i]-'a'); sam.topsort(); return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· 赶AI大潮:在VSCode中使用DeepSeek及近百种模型的极简方法
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地