求最长回文串
后缀数组倍增直接跑果断T了 然后dc3+lcp应该可以过吧 (下次试验一下)
manacher是一个新姿势 复杂度竟然是O(n)
具体是这样写的 先把字符串变成@#c1#c2#。。。#cn¥
这样整个串的长度就变成了len*2+3 也就是说下标变成了 0~len*2+2
然后记录每一个字符最多能往右边衍生的长度
神奇的事情出现了 回文串长度就是这个数字-1
那么manacher优化的地方就很显而易见了 因为回文是对程的 那么也就是说左边的长度很有可能与右边能拓展的长度
相同 那么我们只要能够得到右边最小的能判定衍生的长度 然后再暴力往右衍生就好了
与此同时我们要维护回文最多能覆盖的区域的半径
至此manacher就已经完成了
其实最重要的一步是i+p[i]>mx
#include<stdio.h>
#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxn (111111<<1)
char s[maxn],ss[maxn];
int p[maxn];
int manacher(int n){
memset(p,0,sizeof p);
p[0]=p[1]=1;
int id=1,ans=0,mx=0;
for(int i=2;i<n;++i){
if(mx>i){
p[i]=min(p[id*2-i],mx-i);
}
else p[i]=1;
for(;s[i-p[i]]==s[i+p[i]];p[i]++);
if(i+p[i]>mx){
mx=i+p[i];id=i;
}
ans=max(ans,p[i]);
}
// for(int i=0;i<n;++i)printf("%d ",p[i]);printf("\n");
return ans-1;
}
int main(){
while(~scanf("%s",ss)){
int len=(int)strlen(ss);
len=2*len+2;
for(int i=0;i<=len;++i){
if(!i)s[i]='@';
else if(i==len)s[i]='$';
else if(i&1)s[i]='#';
else s[i]=ss[i/2-1];
}
// cout<<s<<endl;
printf("%d\n",manacher(len));
}
return 0;
}