1. 程式人生 > >2018.12.20【APIO2014】【BZOJ3676】【洛谷P3649】迴文串(迴文自動機PAM)

2018.12.20【APIO2014】【BZOJ3676】【洛谷P3649】迴文串(迴文自動機PAM)

BZOJ傳送門

洛谷傳送門


解析:

PAM裸題,當然SAM也可以做。

先建立出PAM,同時每次更新last節點的cnt,然後再在fail樹上一路向上跳同時上傳cnt就行了。


程式碼:

#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 PAM_node *point;
struct
PAM_node{ int len,cnt; point fa,son[26]; }; cs int N=300005; struct PAM{ PAM_node nd[N]; point last,now; int n;char s[N]; PAM(){ s[0]='#'; nd[0].fa=nd+1; nd[1].fa=nd; nd[0].len=0; nd[1].len=-1; last=nd;now=nd+1; } inline void
push_back(char c){ c-='a';s[++n]=c; while(s[n-1-last->len]!=c)last=last->fa; if(!last->son[c]){ ++now; now->len=last->len+2; point q=last->fa; while(s[n-q->len-1]^c)q=q->fa; now->fa=q->
son[c]; if(!now->fa)now->fa=nd; last->son[c]=now; } last=last->son[c]; ++last->cnt; } inline ll calc(){ re ll ans=0; for(point re i=now;i>nd+1;--i){ i->fa->cnt+=i->cnt; ans=max(ans,(ll)i->cnt*i->len); } return ans; } }pam; char s[N];int len; signed main(){ len=fread(s+1,1,N-1,stdin); for(int re i=1;i<len;++i)pam.push_back(s[i]); printf("%lld",pam.calc()); return 0; }