题目
给你一个由小写拉丁字母组成的字符串
s
s
s。我们定义
s
s
s 的一个子串的存在值为这个子串在
s
s
s 中出现的次数乘以这个子串的长度。
对于给你的这个字符串
s
s
s,求所有回文子串中的最大存在值。
思路
一题多解
如有不会的算法可参考这里学习.
A A A
S A M + M a n a c h e r + 倍 增 SAM+Manacher+倍增 SAM+Manacher+倍增
用
M
a
n
a
c
h
e
r
Manacher
Manacher遍历出所有的回文串,可以知道最多有
O
(
n
)
O(n)
O(n)个.
对找到的回文串
s
[
l
.
.
.
r
]
s[l...r]
s[l...r]在
S
a
m
Sam
Sam中找到对应的状态.
处理方法为:找到前缀
r
r
r的位置,并不停跳后缀链接.
由于最多跳
O
(
n
)
O(n)
O(n)次,我们考虑用倍增预处理.
时间复杂度: O ( n log n ) O(n\log n) O(nlogn)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=6e5+10;
char s[N];
struct node {
int len,fa,v[26];
}tr[N];
int last,tot,fa[N][20],f[N],c[N>>1],b[N],pos[N>>1],n,t;
void add(int c) {
int p=last,x=last=++tot; tr[x].len=tr[p].len+1;
for( ;p&&!tr[p].v[c];p=tr[p].fa) tr[p].v[c]=x;
if(!p) tr[x].fa=1;
else {
int q=tr[p].v[c],y;
if(tr[p].len==tr[q].len-1) tr[x].fa=q;
else {
tr[y=++tot]=tr[q];
tr[y].len=tr[p].len+1;
tr[q].fa=tr[x].fa=y;
for( ;p&&tr[p].v[c]==q;p=tr[p].fa) tr[p].v[c]=y;
}
}
}
void bt() {
last=tot=1;
for(int i=1;s[i];i++) n++,add(s[i] -= 'a'),pos[i]=last;
for(t=0;(1<<t+1)<=n;t++);
for(int i=1;i<=tot;i++) c[tr[i].len]++;
for(int i=1;i<=n;i++) c[i]+=c[i-1];
for(int i=tot; i;i--) b[c[tr[i].len]--]=i;
for(int i=1,p=1;i<=n;i++) p=tr[p].v[s[i]],f[p]++;
for(int i=tot,j; i;i--) j=b[i],f[tr[j].fa]+=f[j];
for(int i=1,j;i<=tot;i++) {
j=b[i];
fa[j][0]=tr[j].fa;
for(int k=0;fa[j][k];k++)
fa[j][k+1]=fa[fa[j][k]][k];
}
}
ll ans;
void calc(int l,int r) {
int x=pos[r],len=r-l+1;
if(!x) return ;
for(int i=t;i>=0;i--)
if(tr[fa[x][i]].len>=len)
x=fa[x][i];
ans=max(ans,(ll)f[x]*len);
}
int p[N];
void Manacher() {
for(int i=n; i;i--) s[i*2]=s[i],s[i*2-1]='#';
s[n=n*2+1]='#';
int pos=0,ed=0;
for(int i=2;i<n;i++) {
if(i<ed) p[i]=min(ed-i,p[pos*2-i]);
else p[i]=1;
calc(i-p[i]+2>>1,i+p[i]-1>>1);
while(i-p[i]>0&&s[i-p[i]]==s[i+p[i]]) {
if(s[i-p[i]]^'#')
calc((i-p[i])>>1,(i+p[i])>>1);
p[i]++;
}
if(i+p[i]>ed) ed=i+p[i],pos=i;
}
printf("%lld\n",ans);
}
int main() {
scanf("%s",s+1);
bt(); Manacher();return 0;
}
B B B
求 S A SA SA+ M a n a c h e r Manacher Manacher+二分+rmq
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=6e5+10,M=N;
char s[M];
int n,m,t,Log[N],wa[N],wb[N],wv[N],c[N],sa[N],rk[N],height[N],f[N][20];
ll ans;
bool cmp(int *x,int i,int j,int k) {
return x[i]==x[j]&&x[i+k]==x[j+k];
}
void DA() {
int *x=wa,*y=wb,i,j,p;
for(int i=1;i<=m;i++) c[i]=0;
for(int i=1;i<=n;i++) c[x[i]=s[i]]++;
for(int i=2;i<=m;i++) c[i]+=c[i-1];
for(int i=n;i>=1;i--) sa[c[x[i]]--]=i;
for(j=p=1;p<n;m=p,j=j*2) {
for(p=0,i=n-j+1;i<=n;i++) y[++p]=i;
for(i=1;i<=n;i++) if(sa[i]>j) y[++p]=sa[i]-j;
for(i=1;i<=n;i++) wv[i]=x[y[i]];
for(i=1;i<=m;i++) c[i]=0;
for(i=1;i<=n;i++) c[wv[i]]++;
for(i=2;i<=m;i++) c[i]+=c[i-1];
for(i=n;i>=1;i--) sa[c[wv[i]]--]=y[i];
swap(x,y); p=x[sa[1]]=1;
for(i=2;i<=n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p:++p;
}
for(i=1;i<=n;i++) rk[sa[i]]=i;
for(i=1,p=0;i<=n;height[rk[i++]]=p)
for(p?p--:0,j=sa[rk[i]-1];s[i+p]==s[j+p];p++);
for(i=n;i>=1;i--) {
f[i][0]=height[i];
for(j=0;p=f[i][j];j++)
f[i][j+1]=min(p,f[i+(1<<j)][j]);
}
}
int Min(int x,int y) {
if(x==y) return N;
if(x>y) swap(x,y);
x++;
int z=Log[y-x+1];
return min(f[x][z],f[y-(1<<z)+1][z]);
}
int find1(int x,int len) {
int l=1,r=x,mid;
while(l<r) {
mid=(l+r)>>1;
if(Min(mid,x)>=len) r=mid;
else l=mid+1;
}
return l;
}
int find2(int x,int len) {
int l=x,r=n,mid;
while(l<r) {
mid=(l+r+1)>>1;
if(Min(x,mid)>=len) l=mid;
else r=mid-1;
}
return l;
}
void calc(int l,int r) {
if(!r) return ;
int len=r-l+1;
int x=find1(rk[l],len),y=max(find2(rk[l]-1,len),rk[l]);
ans=max(ans,(ll)len*(y-x+1));
}
int p[N];
void Manacher() {
for(int i=n; i;i--) s[i*2]=s[i],s[i*2-1]='#';
s[n=n*2+1]='#';
int pos=0,ed=0;
for(int i=2;i<n;i++) {
if(i<ed) p[i]=min(ed-i,p[pos*2-i]);
else p[i]=1;
calc(i-p[i]+2>>1,i+p[i]-1>>1);
while(i-p[i]>0&&s[i-p[i]]==s[i+p[i]]) {
if(s[i-p[i]]^'#')
calc((i-p[i])>>1,(i+p[i])>>1);
p[i]++;
}
if(i+p[i]>ed) ed=i+p[i],pos=i;
}
printf("%lld\n",ans);
}
int main() {
scanf("%s",s+1); n=strlen(s+1); m=122;
for(int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
t=Log[n]; DA(); Manacher();
return 0;
}
C C C
回文自动机PAM
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=3e5+10;
char s[N];
namespace PAM {
int tr[N][26],len[N],fail[N],cnt[N],last,tot;
ll ans;
void init() {
memset(tr,0,(tot+1)*26<<2);
last=tot=1;
len[0]=0; len[1]=-1;
fail[0]=1;
}
int Find(int x,int n) {
while(s[n-len[x]-1]^s[n]) x=fail[x];
return x;
}
void bt() {
init();
for(int i=1,p,x,c;s[i];i++) {
c=s[i]-'a';
p=Find(last,i);
if(!tr[p][c]) {
len[x=++tot]=len[p]+2;
fail[x]=tr[Find(fail[p],i)][c];
tr[p][c]=x;
}
last=tr[p][c];
cnt[last]++;
}
ans=0;
for(int i=tot; i;i--)
ans=max(ans,(ll)len[i]*cnt[i]),
cnt[fail[i]]+=cnt[i];
printf("%lld\n",ans);
}
}
int main() {
s[0]=-1; scanf("%s",s+1);
PAM::bt();return 0;
}