1040 Longest Symmetric String + L2-008 最长对称子串 [Manacher]
这题O(n^2)的方法能A,但是我们还有Manacher算法可以用。之前学这个还懵逼了好久,太菜了。
两个一样的题,放一起了
这里简单写一写
Manacher用一种巧妙的方法把奇偶数长度的回文串都考虑进去,那就是字符填充。aba填充为#a#b#a#,abba填充为#a#b#b#a#。为了防越界,一般还在字符串前加一个符号,如¥#a#b#a#。
接下来有一个数组p[i]用来记录以字符s[i]为中心的最长回文串半径,p[i]-1正好是原字符串中回文串的总长度。例子证明就不写了。
为了得到p[i],我们需要两个辅助变量,id记录最大回文子串的中心位置,max记录最大的p[id]+id,也就是最大回文子串的边界。接下来就是算法的重点了。尝试直接用文字描述
假设当前我们在求p[i],如果在j=2*id-i(s[j]与s[i]关于id位置对称,j<i)处的 p[j]<max-i,也就是j处的回文串包含在id处的回文串内,那么因为ij对称,所以必有p[i]=p[j]。
那如果p[j]>max-i,即j处的回文串左边超出了id的回文串范围,那么这时候在id回文串内的部分至少还是相同的,max后面的需要继续匹配了
如果max<=i,即i不在当前最大回文串范围内,那只能然p[i]=1,然后再去匹配了,详见代码~
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define maxn 2005 using namespace std; string ts,s; int p[maxn]; int main() { getline(cin,ts); s+='@'; s+='#'; for(int i=0;i<ts.length();i++) { s=s+ts[i]+'#'; } int maxx=0,id=0,ans=0; for(int i=1;i<s.length();i++) { if(maxx>i) p[i]=min(maxx-id,p[2*id-i]); else p[i]=1; while(s[i+p[i]]==s[i-p[i]]) p[i]++; if(p[i]+i>maxx) { maxx=p[i]+i; id=i; } ans=max(ans,p[i]); } cout<<ans-1<<endl; }