传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3676
思路:首先要知道一个结论,本质不同的回文串的个数是O(n)的。
从manacher的过程就可以看出来,使最远边界扩展的回文串才是与之前本质不同的,边界只会扩展到n,所以个数是O(n)的
然后对于每个本质不同的字符串,在后缀数组里向上向下二分,找出它的出现次数即可得到答案。
(为什么正常的ST表TLE了....非得改成莫名其妙的O(logn)回答的才AC...)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn=600010;
const double eps=1e-10;
using namespace std;
int n,t1[maxn],t2[maxn],rank[maxn],sa[maxn],sum[maxn],h[maxn],st[maxn>>1][20],f[maxn];char s[maxn],b[maxn];long long ans;
void getsa(){
int *x=t1,*y=t2,p=0,m=255;
for (int i=1;i<=n;i++) sum[x[i]=s[i]]++;
for (int i=1;i<=m;i++) sum[i]+=sum[i-1];
for (int i=1;i<=n;i++) sa[sum[x[i]]--]=i;
for (int j=1;p<n;j<<=1,m=p){
p=0;
for (int i=n-j+1;i<=n;i++) y[++p]=i;
for (int i=1;i<=n;i++) if (sa[i]>j) y[++p]=sa[i]-j;
memset(sum,0,sizeof(sum));
for (int i=1;i<=n;i++) sum[x[y[i]]]++;
for (int i=1;i<=m;i++) sum[i]+=sum[i-1];
for (int i=n;i;i--) sa[sum[x[y[i]]]--]=y[i];
swap(x,y),x[sa[1]]=p=1;
for (int i=2;i<=n;i++){
if (y[sa[i]]!=y[sa[i-1]]||y[sa[i]+j]!=y[sa[i-1]+j]) p++;
x[sa[i]]=p;
}
}
memcpy(rank,x,sizeof(rank));
}
void geth(){
for (int i=1,j=0;i<=n;i++){
if (rank[i]==1) continue;
while (s[i+j]==s[sa[rank[i]-1]+j]) j++;
h[rank[i]]=j;
if (j>0) j--;
}
}
void getst(){
for (int i=1;i<=n;i++) st[i][0]=h[i];
for (int j=1;(1<<j)<=n;j++)
for (int i=1;i+(1<<(j-1))-1<=n;i++)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
inline int getmin(int l,int r){
/*int k=log2(r-l+1);
return min(st[l][k],st[r-(1<<k)+1][k]);*/
int len=r-l+1,k=0,now=1;
for (int i=0;i<=20;i++){
if (now*2>=len){k=i;break;}
now<<=1;
}
return min(st[l][k],st[r-(1<<k)+1][k]);
}
int query(int x,int k){
int l,r,mid,ansl,ansr;
if (h[x+1]<k) ansr=x;
else{
l=x+1,r=n;
while (l<=r){
mid=(l+r)>>1;
if (getmin(x+1,mid)>=k) ansr=mid,l=mid+1;
else r=mid-1;
}
}
if (h[x]<k) ansl=x;
else{
l=1,r=x-1;
while (l<=r){
mid=(l+r)>>1;
if (getmin(mid+1,x)>=k) ansl=mid,r=mid-1;
else l=mid+1;
}
}
return ansr-ansl+1;
}
void manacher(){
int i,mx=1,id=1;
for (b[0]='$',b[1]='#',i=1;i<=n;i++) b[i<<1]=s[i],b[(i<<1)|1]='#';
n=(n<<1)|1;b[n+1]='\0';
//printf("%s\n",b);
for (int i=1;i<=n;i++){
f[i]=min(f[(id<<1)-i],mx-i);
for (;i>=f[i]&&b[i-f[i]]==b[i+f[i]];) f[i]++;
f[i]--;
if (i+f[i]>mx){
for (int j=mx+1;j<=i+f[i];j++){
if (!(j&1)){
//printf("%d %d\n",j-i+1,query(rank[(i+i-j)>>1],j-i+1));
ans=max(ans,1ll*(j-i+1)*query(rank[(i+i-j)>>1],j-i+1));
}
//printf("ans%d %lld\n",j,ans);
}
mx=i+f[i],id=i;
}
}
printf("%lld\n",ans);
}
int main(){
scanf("%s",s+1),n=strlen(s+1);
getsa(),geth(),getst(),manacher();
return 0;
}