搞回文串很容易想到manacher
把每个回文串看成线段
那就是求两个相邻线段的最长总长度
设 l[ i ] 表示左端点为 i-1 时线段的最大长度,r[ i ] 表示右端点为 i+1 时线段的最大长度
(这里 i 在manacher处理后的字符串a上,线段的最大长度是指原字符串上的长度)
那么ans=max(ans, l[ i ] + r[ i ] ) (a[ i ] == ' # ')
当 i 刚好为长线段的端点时的 l[ i ] 和 r[ i ] 在manacher 时可以处理好
当 i 在长线段的内部时 l[ i ] 和 r[ i ] 可以递推出来
l [ i ] =max(l[ i ],l[ i-2 ] -2) (i-2是因为 i 在a上,l[ i-2 ] - 2 是因为要保持回文,左右两边都要去掉)
r [ i ] 也差不多处理
具体看代码:
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; const int N=1e7+7; char s[N],a[N]; int f[N],l[N],r[N],ans,len; inline void read_s() { char ch=getchar(); while(ch<'a'||ch>'z') ch=getchar(); while(ch>='a'&&ch<='z') s[++len]=ch,ch=getchar(); } int main() { read_s(); len=len*2+1; for(int i=1;i<=len;i++) a[i]= i&1 ? '#' : s[i>>1]; a[0]='$'; int pos=0,mx=0; for(int i=1;i<=len;i++) { f[i]= i>=mx ? 1 : min(f[pos*2-i],mx-i); while(a[i+f[i]]==a[i-f[i]]) f[i]++; if(i+f[i]>mx) mx=i+f[i],pos=i; l[i-f[i]+1]=max(l[i-f[i]+1],f[i]-1); r[i+f[i]-1]=max(r[i+f[i]-1],f[i]-1); } for(int i=3;i<len;i+=2) l[i]=max(l[i],l[i-2]-2);//只要计算'#'的l,r数组 for(int i=len-2;i>=3;i-=2) r[i]=max(r[i],r[i+2]-2); for(int i=3;i<len;i+=2) ans=max(ans,l[i]+r[i]);//主要i!=1&&i!=len,题目要求线段长度不能为0 printf("%d",ans); return 0; }