传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3676
思路:首先要知道一个结论,本质不同的回文串的个数是O(n)的。
从manacher的过程就可以看出来,使最远边界扩展的回文串才是与之前本质不同的,边界只会扩展到n,所以个数是O(n)的
然后对于每个本质不同的字符串,在后缀数组里向上向下二分,找出它的出现次数即可得到答案。
(为什么正常的ST表TLE了....非得改成莫名其妙的O(logn)回答的才AC...)
#include
#include
#include
#include
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;pj) 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<=len){k=i;break;}
now<<=1;
}
return min(st[l][k],st[r-(1<>1;
if (getmin(x+1,mid)>=k) ansr=mid,l=mid+1;
else r=mid-1;
}
}
if (h[x]>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;
}