题意:一个子串的价值被定义为长度*出现次数,求价值最大的回文子串
Sol:
首先本质不同的回文子串个数是O(n)级别的,可以用Manacher求出
然后就是要求一个子串的出现次数
可以用后缀数组+二分求,也可以用后缀自动机
定位到子串所属前缀在自动机上的位置,要在Parent树上找这个点到根路径上满足 len ∈ [min,max] 的节点的 Right 集合大小
因为max 满足单调性 可以倍增二分
时间复杂度O(nlogn)
然而这是一道回文数据结构的裸题...挖个坑以后学学吧
Code:
#include<bits/stdc++.h>
#define debug(x) cout<<#x<<"="<<x<<endl
#define PAD(x,y) memset(x,y,sizeof x)
#define CPY(x,y) memcpy(x,y,sizeof x)
using namespace std;
const int maxn = 600009, alpha = 26;
const int Log = 20;
struct SAM
{
int tot,last,root;
struct state
{
int son[alpha];
int mx,siz,par;
}node[maxn];
int dis[maxn][Log+1],c[maxn],pos[maxn];
void init()
{
tot=last=root=1;
PAD(node,0);
}
int extend(int x)
{
int p=last,np=++tot;
node[np].siz=1;
node[np].mx=node[p].mx+1;
while(p&&node[p].son[x]==0)
node[p].son[x]=np,p=node[p].par;
if(p==0) node[np].par=root;
else
{
int q=node[p].son[x];
if(node[p].mx+1==node[q].mx) node[np].par=q;
else
{
int nq=++tot;
node[nq].mx=node[p].mx+1;
CPY(node[nq].son,node[q].son);
node[nq].par=node[q].par;
node[np].par=node[q].par=nq;
while(p&&node[p].son[x]==q)
node[p].son[x]=nq,p=node[p].par;
}
}
last=np;
return last;
}
void build()
{
for(int i=1;i<=tot;i++) c[node[i].mx]++;
for(int i=1;i<=tot;i++) c[i]+=c[i-1];
for(int i=1;i<=tot;i++) pos[c[node[i].mx]--]=i;
for(int i=1;i<=tot;i++)
{
int x=pos[i];
if(!node[x].par) dis[x][0]=x;
else dis[x][0]=node[x].par;
for(int j=1;j<=Log;j++) dis[x][j]=dis[dis[x][j-1]][j-1];
}
for(int i=tot;i>=1;i--)
{
int x=pos[i],y=node[x].par;
node[y].siz+=node[x].siz;
}
}
int query(int idx,int tar)
{
for(int i=Log;i>=0;i--)
if(node[dis[idx][i]].mx>=tar)
idx=dis[idx][i];
return node[idx].siz;
}
}uuz;
char str[maxn],s[maxn];
int pos[maxn],p[maxn];
int n,len;
long long ans;
void update(int end,int length)
{
if(!pos[end]) return ;
ans=max(ans,1ll*length*uuz.query(pos[end],length));
}
void Manacher()
{
int now=0,idx=0;
for(int i=1;i<=len;i++)
{
if(now>i) p[i]=min(now-i,p[idx*2-i]);
else p[i]=0,update(i,1);
while(s[i+p[i]+1]==s[i-p[i]-1])
{
p[i]++;
if(i+p[i]>now)
{
update(i+p[i],p[i]+1);
now=i+p[i];idx=i;
}
}
}
}
int main()
{
scanf("%s",str+1);n=strlen(str+1);
s[0]='$';s[++len]='#';uuz.init();
for(int i=1;i<=n;i++)
{
s[++len]=str[i];
pos[len]=uuz.extend(s[len]-'a');
s[++len]='#';
}
uuz.build();
Manacher();
cout<<ans<<endl;
return 0;
}