传送门
对原串建立一个后缀自动机,然后用反串在上面匹配。
如果当前匹配的区间
[
l
,
r
]
[l,r]
[l,r]包裹了当前状态的
e
n
d
p
o
s
endpos
endpos中的最大值,那么
[
l
,
m
a
x
p
o
s
]
[l,maxpos]
[l,maxpos]就是一个回文串。
于是赶快码一波统计答案(很遗憾会wa)
因为有可能原串在答案中。
于是我们可以遍历其
l
i
n
k
link
link链一直跳来更新答案。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
typedef long long ll;
const int N=6e5+5;
int n;
char s[N];
struct SAM{
int len[N],son[N][26],link[N],siz[N],pos[N],cnt[N],rk[N],tot,rt,last;
bool vis[N];
SAM(){tot=rt=last=1,len[0]=-1;for(ri i=0;i<26;++i)son[0][i]=0;}
inline void expand(int x,int Pos){
int p=last,np=++tot;
siz[last=np]=1,pos[np]=Pos,len[np]=len[p]+1;
while(p&&!son[p][x])son[p][x]=np,p=link[p];
if(!p){link[np]=rt;return;}
int q=son[p][x],nq;
if(len[q]==len[p]+1){link[np]=q;return;}
len[nq=++tot]=len[p]+1,memcpy(son[nq],son[q],sizeof(son[q])),link[nq]=link[q];
while(p&&son[p][x]==q)son[p][x]=nq,p=link[p];
link[np]=link[q]=nq;
}
inline void topsort(){
for(ri i=1;i<=tot;++i)++cnt[len[i]];
for(ri i=2;i<=last;++i)cnt[i]+=cnt[i-1];
for(ri i=1;i<=tot;++i)rk[cnt[len[i]]--]=i;
for(ri i=tot;i;--i)siz[link[rk[i]]]+=siz[rk[i]],pos[link[rk[i]]]=max(pos[link[rk[i]]],pos[rk[i]]);
}
inline void query(){
ll ans=0;
int p=1,nowlen=0;
for(ri i=n;i;--i){
while(p!=rt&&!son[p][s[i]-'a'])p=link[p],nowlen=len[p];
if(son[p][s[i]-'a'])++nowlen,p=son[p][s[i]-'a'];
if(pos[p]<i+nowlen){
if(i<=pos[p])ans=max(ans,(ll)(pos[p]-i+1)*siz[p]);
for(ri nowp=link[p];nowp&&!vis[nowp];nowp=link[nowp]){
vis[nowp]=1;
if(i<=pos[nowp]&&i+len[nowp]-1>=pos[nowp])ans=max(ans,(ll)(pos[nowp]-i+1)*siz[nowp]);
}
}
}
cout<<ans;
}
}sam;
int main(){
scanf("%s",s+1),n=strlen(s+1);
for(ri i=1;i<=n;++i)sam.expand(s[i]-'a',i);
sam.topsort(),sam.query();
return 0;
}