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,然后再去匹配了,详见代码~

#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;
}
View Code

 

posted on 2019-03-13 21:19  FTA_Macro  阅读(90)  评论(0编辑  收藏  举报

导航