代码总用时:3h
很简单的一道题,只要意识到Manacher算法的本质(本质不同的回文串的个数是O(n)的),配合后缀自动机或者后缀数组就可以轻松解决。
但这道题调了好久,浪费了很多时间,一是因为后缀自动机模板不熟练,而是Manacher算法流程没有一个清楚的认识。
写代码的时候精力要高度集中,不能因为低级错误耽误时间。
下面是SAM版本的代码:
#include<cstdio> #include<cstring> #include<algorithm> #define rep(i,l,r) for (int i=l; i<=r; i++) typedef long long ll; using namespace std; const int N=600100; int cnt=1,lst=1,n,tot[N],mx[N],p[N],pos[N],son[N][27],fa[N],f[N][20],q[N],R[N]; ll ans; char s[N],S[N]; void ext(int c,int x){ int p=lst,np=lst=++cnt; mx[np]=mx[p]+1; R[np]=1; pos[x]=np; while (!son[p][c] && p) son[p][c]=np,p=fa[p]; if (!p) fa[np]=1; else{ int q=son[p][c]; if (mx[q]==mx[p]+1) fa[np]=q; else{ int nq=++cnt; mx[nq]=mx[p]+1; memcpy(son[nq],son[q],sizeof(son[q])); fa[nq]=fa[q]; fa[q]=fa[np]=nq; while (son[p][c]==q && p) son[p][c]=nq,p=fa[p]; } } } void pre(){ rep(i,1,cnt) tot[mx[i]]++; rep(i,1,n) tot[i]+=tot[i-1]; for (int i=cnt; i; i--) q[tot[mx[i]]--]=i; for (int i=cnt; i; i--) R[fa[q[i]]]+=R[q[i]]; rep(i,1,cnt){ f[i][0]=fa[i]; rep(j,1,19) f[i][j]=f[f[i][j-1]][j-1]; } } void get(int l,int r){ l=(l>>1)+(l&1); r>>=1; int x=pos[r]; for (int i=19; ~i; i--) if (mx[f[x][i]]>=r-l+1) x=f[x][i]; ans=max(ans,1ll*R[x]*(r-l+1)); } void manacher(){ int mxlen=0,id; rep(i,1,n){ if (mxlen>i) p[i]=min(mxlen-i,p[2*id-i]); else{ p[i]=1; if (S[i]!=‘#‘) get(i,i); } while (S[i+p[i]]==S[i-p[i]]) get(i-p[i],i+p[i]),p[i]++; if (p[i]+i>mxlen) mxlen=p[i]+i,id=i; } } int main(){ freopen("palindromes.in","r",stdin); freopen("palindromes.out","w",stdout); scanf("%s",s+1); n=strlen(s+1); rep(i,1,n) ext(s[i]-‘a‘,i); pre(); S[0]=‘$‘; S[1]=‘#‘; rep(i,1,n) S[(i<<1)+1]=‘#‘,S[i<<1]=s[i]; n=(n<<1)+1; manacher(); printf("%lld\n",ans); return 0; }