题解:
这篇题解是关于manacher+SAM的。
PS.PAM已更新。
因为我还不会回文自动机我会学的
SAM支持给出一个串,求出现次数。
manacher支持找回文串。
然后放在一起,当每个节点回文半径扩展时查询。
这样时间是O(n^2)的。
为了时间,我们可以O(nlogn)预处理每个节点沿pre指针条2^k次到哪个点。
然后查询O(nlogn)。
貌似只有bz卡空间?
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 300050 #define ll long long char s0[N],s1[2*N]; int len,n; struct node{int pre,len,trs[26];}p[2*N]; int siz[2*N],rt[N]; struct SAM { int tot,las; SAM(){tot=las=1;} int insert(int c) { int np,nq,lp,lq; np=++tot; siz[np]=1; p[np].len = p[las].len+1; for(lp=las;lp&&!p[lp].trs[c];lp=p[lp].pre) p[lp].trs[c]=np; if(!lp)p[np].pre = 1; else { lq = p[lp].trs[c]; if(p[lq].len==p[lp].len+1)p[np].pre = lq; else { nq=++tot; p[nq]=p[lq]; p[nq].len = p[lp].len+1; p[lq].pre = p[np].pre = nq; while(p[lp].trs[c]==lq) { p[lp].trs[c]=nq; lp=p[lp].pre; } } } return las = np; } int hs[2*N],topo[2*N],fa[2*N][21]; int i,j,x; void build() { for(i=1;i<=tot;i++)hs[p[i].len]++; for(i=1;i<=tot;i++)hs[i]+=hs[i-1]; for(i=1;i<=tot;i++)topo[hs[p[i].len]--]=i; for(i=tot;i>=1;i--) { x = topo[i]; siz[p[x].pre]+=siz[x]; fa[x][0]=p[x].pre; } for(i=1;i<=tot;i++) { x = topo[i]; for(j=1;j<=20;j++) fa[x][j]=fa[fa[x][j-1]][j-1]; } } int len; int query() { x = rt[x]; for(i=20;i>=0;i--) { if(p[fa[x][i]].len>=len) { x=fa[x][i]; } } return x; } }sam; void init() { s1[0]='!'; s1[++n]='#'; for(int i=1;i<=len;i++) { s1[++n]=s0[i]; s1[++n]='#'; } s1[n+1]='@'; } int rp[2*N]; ll manacher() { init(); ll ans = 0; int mid = 0,mx = 0,i,u; for(i=1;i<=n;i++) { if(i<=mx)rp[i]=min(rp[2*mid-i],mx-i+1); else { rp[i]=1; if(i%2==0)ans=max(ans,1ll*siz[p[1].trs[s1[i]-'a']]); } while(s1[i-rp[i]]==s1[i+rp[i]]) { rp[i]++; if((i-rp[i]+1)%2==0) { sam.x = (i+rp[i]-1)/2,sam.len = rp[i]; u = sam.query(); ans = max(ans,1ll*siz[u]*rp[i]); } } if(i+rp[i]-1>mx)mx=i+rp[i]-1,mid=i; } return ans; } int main() { scanf("%s",s0+1); len = strlen(s0+1); for(int i=1;i<=len;i++) rt[i]=sam.insert(s0[i]-'a'); sam.build(); printf("%lld ",manacher()); return 0; }
这里是回文自动机:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 300050 #define ll long long char s[N]; ll ans; struct node { int trs[28],pre,len; ll wgt; }p[N]; struct PAM { int las,tot; PAM() { las = tot = 1; p[0].pre = p[1].pre = 1; p[1].len = -1; } bool mis(int i,int x) { return s[i]!=s[i-p[x].len-1]; } void insert(int i) { int np,lp,tmp; lp = las; int c = s[i]-'a'+1; while(mis(i,lp))lp=p[lp].pre; if(!p[lp].trs[c]) { np=++tot; p[np].len = p[lp].len+2; tmp=p[lp].pre; while(mis(i,tmp))tmp=p[tmp].pre; p[np].pre = p[tmp].trs[c]; p[lp].trs[c]=np; } las = p[lp].trs[c]; p[las].wgt++; } void build() { for(int i=tot;i>=1;i--) { p[p[i].pre].wgt+=p[i].wgt; ans = max(ans,1ll*p[i].len*p[i].wgt); } } }pam; int main() { scanf("%s",s+1); int len = strlen(s+1); for(int i=1;i<=len;i++) pam.insert(i); pam.build(); printf("%lld ",ans); return 0; }