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

【模板】字尾自動機SAM

參考題目:洛谷P3804


解析:

其實這個東西的理解的話,說難沒有那麼難,說簡單也不是很簡單。
這裡先貼一個程式碼,什麼時候再更新吧。


程式碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

typedef struct SAM_node *point;
struct SAM_node{
    int len,
cnt; point fa,son[26]; SAM_node():len(0),fa(NULL){memset(son,0,sizeof son);} inline point clear(int l=0){ fa=NULL; len=l; memset(son,0,sizeof son); return this; } }; cs int N=1000006; struct SAM{ SAM_node nd[N<<1]; point now,last,pos[N<<1];
int bin[N<<1]; SAM():now(nd),last(nd){} inline void clear(){ for(;now>nd;--now)now->clear(); last=now=nd->clear(); } inline void push_back(char c){ c-='a'; point cur=++now; cur->len=last->len+1; cur->cnt=
1; point p=last; for(;p&&!p->son[c];p=p->fa)p->son[c]=cur; if(!p)cur->fa=nd; else if(p->son[c]->len==p->len+1)cur->fa=p->son[c]; else { point clone=++now,q=p->son[c]; *clone=*q; clone->len=p->len+1; clone->cnt=0; q->fa=cur->fa=clone; for(;p&&p->son[c]==q;p=p->fa)p->son[c]=clone; } last=cur; } inline ll calc(){ re ll ans=0; for(point re i=nd;i<=now;++i)++bin[i->len]; for(int re i=1;i<=now-nd;++i)bin[i]+=bin[i-1]; for(point re i=nd;i<=now;++i)pos[bin[i->len]--]=i; for(int re i=now-nd;i;--i){ if(pos[i]->fa)pos[i]->fa->cnt+=pos[i]->cnt; if(pos[i]->cnt^1)ans=max(ans,(ll)pos[i]->cnt*pos[i]->len); } return ans; } }sam; char s[N];int len; signed main(){ scanf("%s",s+1);len=strlen(s+1); for(int re i=1;i<=len;++i)sam.push_back(s[i]); printf("%lld",sam.calc()); return 0; }