题目大意:求长度为k的串的最大次数,把k从1到length的所有答案全部输出。
思路:
这道题放在$SAM$里就是求长度$k$对应的所有$right$集中最大的大小。
我们以$aabab$这个串距离,称作$S$串。
首先我们要求出每一个状态对应的right集大小,S中的aab和ab此时并不在一个模式下,但他们属于一个right集,而ab是aab的父串,所以我们用拓扑排序的方式得到right集,这里的更新操作是$+$,因为ab对应的模式此时并没有包含aab中的ab。
而得到right后,我们会发现在SAM上并没有一个单独的模式对应b,因为b被包含在了ab这个模式里面,所以我们也要用长度为2的答案来更新长度为1的答案,这里是取max,因为有可能是重复的,比如$abab$这样的串。
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=1000010; char s[maxn]; int len[maxn<<1],ch[maxn<<1][27],fa[maxn<<1],tot=1,root=1,last=1,siz,r[maxn<<1]; int a[maxn<<1],c[maxn<<1],ans[maxn<<1]; void extend(int x){ int now=++tot,pre=last; r[now]=1; last=now,len[now]=len[pre]+1; while( pre && !ch[pre][x]){ ch[pre][x]=now; pre=fa[pre]; } if(!pre)fa[now]=root; else{ int q = ch[pre][x]; if(len[q]==len[pre]+1)fa[now]=q; else { int nows=++tot; memcpy(ch[nows],ch[q],sizeof(ch[q])); len[nows]=len[pre]+1; fa[nows]=fa[q]; fa[q]=fa[now]=nows; while(pre&&ch[pre][x]==q){ ch[pre][x]=nows; pre=fa[pre]; } } } } void topSort(){ for(int i=1;i<=tot;i++)c[len[i]]++; for(int i=1;i<=tot;i++)c[i]+=c[i-1]; for(int i=tot;i>0;i--)a[c[len[i]]--]=i; for(int i=tot;i>0;i--)r[fa[a[i]]]+=r[a[i]]; } int main(){ scanf("%s",s); siz=strlen(s); for(int i=0;i<siz;i++) { int p=s[i]-'a'; extend(p); } topSort(); for(int i=1;i<=tot;i++)ans[len[i]]=max(ans[len[i]],r[i]); for(int i=siz-1;i>0;i--)ans[i]=max(ans[i+1],ans[i]); for(int i=1;i<=siz;i++)printf("%d ",ans[i]); }