洛谷 P4555 [国家集训队]最长双回文串(Manacher)
题目链接:https://www.luogu.com.cn/problem/P4555
首先明白两个回文串,那么要使两个回文串成立,那么我们只能把$'#'$作为中间节点。
然后我们跑一边Manacher,记录$l[],r[]$,$l[i]$表示以$i$开头的最长回文串长度,$r[i]$表示以$i$结尾的最长回文串长度。
那么到最后我们只需要用线性的时间来枚举$i$,找$l_i+r_i$最大即可。
但是,在Manacher算法中有局限性:就是我们处理出来的$l,r$都是饱和回文串的,那么我们就要处理不饱和回文串:
$l[i]=max(l[i],l[i-2]-2)$
$r[i]=max(r[i],r[i+2]-2)$
解释一下$1$式,$2$式类似:
其实都是一个递推的过程,l[i-2]即为上一个$‘#’$的位置,$-2$是因为回文串的对称性。
AC代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 7 const int N=100010; 8 int p[N*2],l[N*2],r[N*2]; 9 char s[N*2],str[N]; 10 int ans,t; 11 12 void manacher(int len){ 13 s[0]='$'; s[++t]='#'; 14 for(int i=1;i<=len;i++){ 15 s[++t]=str[i]; 16 s[++t]='#'; 17 } 18 int pos=0,mx=0; 19 for(int i=1;i<=t;i++){ 20 if(i>mx) p[i]=1; 21 else p[i]=min(p[2*pos-i],mx-i); 22 while(i+p[i]<=t&&i-p[i]>=1&&s[i-p[i]]==s[i+p[i]]) p[i]++; 23 if(i+p[i]>mx){ 24 mx=i+p[i]; 25 pos=i; 26 } 27 l[i-p[i]+1]=max(l[i-p[i]+1],p[i]-1); 28 r[i+p[i]-1]=max(r[i+p[i]-1],p[i]-1); 29 } 30 } 31 32 int main(){ 33 scanf("%s",str+1); 34 manacher(strlen(str+1)); 35 for(int i=3;i<=t;i+=2) l[i]=max(l[i],l[i-2]-2); 36 for(int i=t;i>=3;i-=2) r[i]=max(r[i],r[i+2]-2); 37 for(int i=3;i<=t;i+=2) if(l[i]&&r[i]) ans=max(ans,l[i]+r[i]); 38 printf("%d\n",ans); 39 return 0; 40 }