$SAM$是啥?来一发朴素的$SA$解法。
先把$SA$建出来。如果某两个子串$S_1,S_2$相同的话,它们所属的后缀的$LCP$要大于等于$len(S_1)$。
$LCP$是$\min\{height[k]\}(i<k\le j)$,然后就变成了对每个长度$L$,求出最长的一段区间$[l,r]$使$height[i]\ge L(i\in[l,r])$。单调栈扫两遍就行了。
代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #define maxn 250005 #define inf 0x3f3f3f3f #define pn putchar('\n') #define px(x) putchar(x) #define ps putchar(' ') #define pd puts("======================") #define pj puts("++++++++++++++++++++++") using namespace std; inline int read(){ int x=0,y=0; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return y?-x:x; } int sa[maxn],rk[maxn],hei[maxn],tp[maxn],tax[maxn],ll[maxn],rr[maxn],ans[maxn],n,m; char s[maxn]; struct MonoStack{ int sta[maxn],top; inline void push(int x){ while(top>1&&hei[sta[top]]>=hei[x])--top; sta[++top]=x; } inline int back(){ return sta[top-1]; } inline void clear(){ top=0; } }st;//单调栈 void Rsort(){ for(register int i=0;i<=m;++i)tax[i]=0; for(register int i=1;i<=n;++i)++tax[rk[i]]; for(register int i=1;i<=m;++i)tax[i]+=tax[i-1]; for(register int i=n;i;--i)sa[tax[rk[tp[i]]]--]=tp[i]; } void Ssort(){ for(register int i=1;i<=n;++i)rk[i]=s[i],tp[i]=i; m=225,Rsort(); for(register int k=1,p=0;p<n;m=p,k<<=1){ p=0; for(register int i=1;i<=k;++i)tp[++p]=n-k+i; for(register int i=1;i<=n;++i)if(sa[i]>k)tp[++p]=sa[i]-k; Rsort(); for(register int i=1;i<=n;++i)tp[i]=rk[i]; rk[sa[1]]=p=1; for(register int i=2;i<=n;++i) rk[sa[i]]=tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k]?p:++p; } } void get_height(){ int k=0,x; for(register int i=1;i<=n;++i){ if(rk[i]==1)continue; if(k)--k; x=sa[rk[i]-1]; while(i+k<=n&&x+k<=n&&s[i+k]==s[x+k])++k; hei[rk[i]]=k; } } void solve(){ st.push(0); for(register int i=1;i<=n;++i) st.push(i),ll[i]=st.back()+1; st.clear(),st.push(n+1); for(register int i=n;i;--i) st.push(i),rr[i]=st.back()-1; for(register int i=1;i<=n;++i) ans[hei[i]]=max(ans[hei[i]],rr[i]-ll[i]+2);//先只更新当前答案 ,比hei[i]小的下面做一个后缀最大值取到 ans[n+1]=1;//答案最少为1 for(register int i=n;i;--i) ans[i]=max(ans[i],ans[i+1]); for(register int i=1;i<=n;++i) printf("%d\n",ans[i]); } int main(){ scanf("%s",s+1),n=strlen(s+1); Ssort(),get_height(),solve(); }