题意
求一个字符串中最长回文串的长度。
思路
manachermanachermanacher算法。
首先我们先在字符串空隙中插入符号,以便处理偶数长度的回文串。
设hwihw_ihwi为以iii为中心最多能往旁边扩展的长度,maxrightmaxrightmaxright为当前匹配到的最右边的回文串。
枚举1∼n1\sim n1∼n,如果i<maxrighti<maxrighti<maxright且在midmidmid右边,那么根据回文字符串的对称性,可以知道它的对称点jjj的hwj≤hwihw_j \leq hw_ihwj≤hwi,我们就可以直接用hwjhw_jhwj更新hwihw_ihwi,然后再扩展,要注意用hwjhw_jhwj来更新hwihw_ihwi不能使i+hwii+hw_ii+hwi超过maxrightmaxrightmaxright,因为不一定满足对成性。
如果i>maxrighti>maxrighti>maxright就从111开始来扩展。
如果扩展完后的位置>maxright>maxright>maxright,我们就可以更新它和midmidmid。
答案就为max{hwi}−1max\{hw_i\}-1max{hwi}−1,因为一开始我们在字符串空隙中插入了符号,所以不用∗2*2∗2。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
int n, ans;
int hw[22000002];
char a[11000000], s[22000002];
void init() {
scanf("%s", a);
s[0] = s[1] = '#';
n = strlen(a);
for (int i = 0; i < n; i++) {
s[i * 2 + 2] = a[i];
s[i * 2 + 3] = '#';
}
n = n * 2 + 2;
s[n] = 0;
}
void manacher() {
int maxright = 0, mid;
for (register int i = 1; i < n; i++) {
if (i < maxright)
hw[i] = std::min(hw[mid * 2 - i], maxright - i);
else hw[i] = 1;
for (; s[i + hw[i]] == s[i - hw[i]]; hw[i]++);//扩展
if (hw[i] + i > maxright) {//更新
maxright = hw[i] + i;
mid = i;
}
ans = std::max(ans, hw[i]);
}
}
int main() {
init();
manacher();
printf("%d", ans - 1);
}