1. 程式人生 > >【字尾自動機】【SAM】學習相關以及模板

【字尾自動機】【SAM】學習相關以及模板

 這是一篇偷懶的文章,主要是今天確實碰到了比較難理解的資料結構。
 之前是以為所有的字尾自動機都可以用字尾陣列代替的,今天做到有一道題hdu6405,似乎並非如此了,主要這題是多串的,所以沒法子字尾陣列,只能字尾自動機(而且還是廣義字尾自動機,相關題解明天補上)
 今天參考的博文
傳送門A
傳送門B
傳送門C
相關的理解和思考以及應用,以後會補上。
附上我的模板(其實是抄傳送門A的),當然這題可以用字尾陣列做。

//給定一個只包含小寫字母的字串SS,
//請你求出 SS 的所有出現次數不為 1 的子串的出現次數乘上該子串長度的最大值。 
#include<cstdio>
#include
<cstring>
#include<algorithm> using namespace std; using LL=long long; const int N=1E6+5,M=2E6+10; char s[N]; int cur,cnt,n,last,ch[M][26],lnk[M],dis[M],sz[M],c[N],sa[M]; LL ans; void build_sam(int c, int id) { last=cur; cur=++cnt; int p=last; dis[cur]=id; for(;p&&!ch[p][c]
;p=lnk[p]) ch[p][c]=cur; if(!p) lnk[cur]=1; else { int q=ch[p][c]; if(dis[q]==dis[p]+1) lnk[cur]=q; else { int nt=++cnt; dis[nt]=dis[p]+1; memcpy(ch[nt],ch[q],sizeof(ch[q])); lnk[nt]=lnk[q]; lnk[q]=lnk[cur]=nt; for(;ch[p][c]==q;p=lnk[p]) ch[p][c]=nt; } } sz[
cur]=1; } void Flower() { for(int i=1;i<=cnt;i++) c[dis[i]]++; for(int i=1;i<=n;i++) c[i]+=c[i-1]; for(int i=cnt;i;i--) sa[c[dis[i]]--]=i; //技巧:相當於dis從大到小排序(這是dp順序),比nlogn快那麼點 for(int i=cnt;i;i--) { int p=sa[i]; if(sz[p]>1) ans=max(ans,(LL)sz[p]*dis[p]); //dp sz[lnk[p]]+=sz[p]; //dp } } int main() { scanf("%s",s+1); n=strlen(s+1); cur=cnt=1; for(int i=1;i<=n;i++) build_sam(s[i]-'a',i); Flower(); printf("%lld",ans); return 0; }