在我还没有博客之前拿分享当 blog 了。
虽然训练指南上没有讲 Manacher……但是这题几乎就是一个裸的 Manacher啊……
然而书上的标签是:有难度,配合数据结构
Tag
Manacher
题意
问给定字符串中最大的W串的长度。其中W串的定义:形式为 ww’w’ 的字符串,w’ 为 w 的反串
思路
根据题目描述,显然 ww’ww’ 和 ww’ 都是回文串。
考虑 Manacher 的原理,不重不漏地枚举了每个回文串,也就是说考虑到了每一个回文串。
先回归暴力,想到可以枚举每个回文串并判断右边是否也是相同的一个回文串。
“枚举每个回文串”,和 Manacher 有相似之处。也就是说,我们是否可以在 Manacher 的运行过程中就完成答案统计?
设现在处理到了第 i 个位置,根据 Manacher 把奇数串转化成偶数串的思想,要求 i 是分隔符 #
.
当 i 位置的回文半径达到 4 的倍数的时候,说明左半边的串长度是偶数,设当前回文半径为 r,显然左半边串的中心位置 $pos=i-r/2
$,如果 pos 处的回文半径不小于 $i-r/2$ ,那么左半边就是回文串,$ans=max( ans,r )$.
代码
#include <bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int n,r[N<<1];
char str[N],s[N<<1];
void manacher()
{
int mx=0,pos=0,len=2*n+1,ans=0;
for ( int i=0; i<len; i++ )
{
if ( i<mx ) r[i]=min( r[2*pos-i],mx-i );
else r[i]=1;
while ( i+r[i]<len && i-r[i]>=0 && s[i+r[i]]==s[i-r[i]] )
{
if ( s[i]=='#' && r[i]%4==0 && r[i-r[i]/2]>=r[i]/2 ) ans=max( ans,r[i] );
r[i]++;
}
if ( i+r[i]>mx ) mx=i+r[i],pos=i;
}
printf( "%d\n",ans );
}
void prework()
{
int pos=0; n=strlen(str);
for ( int i=0; i<n; i++ )
s[pos++]='#',s[pos++]=str[i];
s[pos++]='#';
}
int main()
{
int T; scanf( "%d",&T );
while ( T-- )
{
scanf( "%s",str ); prework();
manacher();
}
}