Manacher算法的应用
求出字符串的最长回文子串。
Manacher算法的流程
1、插入特殊字符
因为回文串的长度可能是奇数或偶数,为了不考虑这么多情况,就插入一些特殊字符。
比如:abcddcba
插入后变成:#a#b#c#d#d#c#b#a#
所以可以将问题转化成求长度为奇数的回文串。
2、求出每一位为中心的最长回文子串
设为以i为中心的最长回文子串。
如何求?
通过前面的信息,首先要求出Maxright和pos。
Maxright为前面所求的回文字符串中最靠右的右端点,pos为Maxright所对应的中心点。
分两种情况讨论:
- i在Maxright的左边。先找到i关于pos的对应点j()。如果将j的回文串复制到i,保证的回文长度为,在这个基础上尽量往两边扩展。
- 否则,保证的回文长度为1,在这个基础上往两边扩展。
然后更新Maxright和pos。
3、统计答案
略
例题
using namespace std;
#include <iostream>
#include <cstring>
#include <algorithm>
char str[1000003];
char s[2000007];
int p[2000007];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T=1;
for (cin>>str;str[0]!='E';++T,cin>>str)
{
int len=1;
s[0]='#';
for (char* ch=str;*ch;++ch)
{
s[len++]=*ch;
s[len++]='#';
}
p[0]=1;
int pos=0,Maxright=0,ans=0;
for (int i=1;i<len;++i)
{
if (i<Maxright)
p[i]=min(p[(pos<<1)-i],Maxright-i);
else
p[i]=1;
int j,k;
for (j=i-p[i],k=i+p[i];j>=0 && k<len && s[j]==s[k];--j,++k);
p[i]=k-i;
if (k-1>Maxright)
{
Maxright=k-1;
pos=i;
}
ans=max(ans,p[i]-1);
}
cout<<"Case "<<T<<": "<<ans<<'
';
}
return 0;
}