manacher 学习笔记(再回首)
这一算法用于求最长回文子串。
思想上和 KMP 类似,都是利用已求出的部分去减少不必要的枚举。
我们设 \(f_i\) 表示以 \(i\) 为中心的最长回文子串长度。假设现在有一个以 \(Q\) 为中心的回文子串,其右边界为 \(mr\),现在需要去求 \(Q\) 点右侧一点 \(p\) 所对应的 \(f_p\),我们设 \(d\) 为 \(p\) 关于 \(Q\) 的对称点,根据回文串的性质,那么有 \(f_p = min(mr-i, f_d)\)。如果到达边界的时候尝试扩展就好了。注意边界条件的判定。
我们又发现,上述过程只能针对长度为奇数的串。那如何处理偶数串呢?我们只需要在原串的缝隙间添上一些无用字符即可。
代码:
int n;
int f[N*2];
char s[N*2], a[N];
int mx;
void manacher()
{
s[0] = '!', s[1] = '#';
for(int i = 1; i<=n; i++)
{
s[i<<1] = a[i];
s[(i<<1)|1] = '#';
}
n = (n<<1)|1, s[n+1] = '/';
for(int i = 1, mr = 1, mid = 0;i<=n; i++)
{
f[i] = i<mr?min(mr-i, f[mid*2-i]):1;
while(s[i+f[i]]==s[i-f[i]]) f[i]++;
if(i+f[i]>mr) mr = i+f[i], mid = i;
}
for(int i = 1; i<=n;i++)
{
mx = max(f[i]-1, mx);
}
}