1. 程式人生 > >洛谷3804 【模板】字尾自動機

洛谷3804 【模板】字尾自動機

題目連結

題意:
給你一個n個字元的字串,求所有出現次數大於1的子串乘子串長度的最大值。n<=1e6

題解:
感覺全機房都早就會後綴自動機了啊,就我不會。而且感覺自己學得還不怎麼樣,似乎不是那麼明白,感覺藥丸。

這個題的話建出字尾自動機之後,我們根據SAM的性質可知,一個點在parent樹的子樹中的葉子節點個數就是根到該節點的子串出現的次數。我們在建字尾自動機的時候已經求出了從根到每個節點的字串長度,那麼我們就在parent樹上dfs一遍,一邊更新子樹內葉子數,一邊乘當前的字串長度更新答案即可。

程式碼:

#include <bits/stdc++.h>
using namespace std; int n,fa[4000010],ch[4000010][27],len[4000010]; char s[1000010]; int hed[4000010],sz[4000010],rt=1,cnt=1,lst=1,num; struct node { int to,next; }a[8000010]; long long ans; inline void insert(int x) { int cur=++cnt,pre=lst; lst=cur; len[cur]=len[pre]+1; sz[cur]=1; for(;pre&&!ch[pre][x];pre=fa[pre]) ch[
pre][x]=cur; if(!pre) fa[cur]=rt; else { int ji=ch[pre][x]; if(len[ji]==len[pre]+1) fa[cur]=ji; else { int gg=++cnt; len[gg]=len[pre]+1; memcpy(ch[gg],ch[ji],sizeof(ch[ji])); fa[gg]=fa[ji]; fa[ji]=fa[cur]=gg; for(;pre&&ch[pre][x]==ji;pre=fa[pre]) ch[pre][
x]=gg; } } } inline void add(int from,int to) { a[++num].to=to; a[num].next=hed[from]; hed[from]=num; } inline void dfs(int x) { for(int i=hed[x];i;i=a[i].next) { int y=a[i].to; dfs(y); sz[x]+=sz[y]; } if(sz[x]>1) ans=max(ans,(long long)sz[x]*len[x]); } int main() { scanf("%s",s+1); n=strlen(s+1); for(int i=1;i<=n;++i) insert(s[i]-'a'); for(int i=2;i<=cnt;++i) add(fa[i],i); dfs(1); printf("%lld\n",ans); return 0; }