题意
输入长度为 n n n的串 S S S,求 S S S的最长双回文子串 T T T,即可将 T T T分为两部分 X , Y , ( ∣ X ∣ , ∣ Y ∣ ≥ 1 ∣ X ∣ , ∣ Y ∣ ≥ 1 ) X,Y,(|X|,|Y|≥1∣X∣,∣Y∣≥1) X,Y,(∣X∣,∣Y∣≥1∣X∣,∣Y∣≥1)且 X X X和 Y Y Y都是回文串。
思路
我们可以设 l i l_i li为以 i i i结尾的回文字符串的最长长度, r i r_i ri为以 i i i开头的回文字符串的最长长度。
求这两个东西我们可以用到 m a n a c h e r manacher manacher算法,算法中每次扩展回文串长度时可以顺便更新一下这两个的值,最后递推把所有空隙位置的两个值更新一下最大值,就可以得出这两个东西了。
有了这两个我们就可以很容易得出答案 a n s = m a x ( l i + r i ) { l i > 0 , r i > 0 } ans=max(l_i+r_i)\{l_i>0,r_i>0\} ans=max(li+ri){li>0,ri>0}
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
int n, ans;
int hw[22000002], l[22000002], r[22000002];
char a[11000000], s[22000002];
void init() {
scanf("%s", a);
s[0] = s[1] = '#';
n = strlen(a);
for (register 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;
}
l[i + hw[i] - 1] = std::max(l[i + hw[i] - 1], hw[i] - 1);//更新l,r
r[i - hw[i] + 1] = std::max(r[i - hw[i] + 1], hw[i] - 1);
}
}
int main() {
init();
manacher();
for (register int i = 2; i < n; i += 2)//递推
r[i] = std::max(r[i], r[i - 2] - 2);//每往里缩,回文长度就会-2
for (register int i = n - 1; i >= 2; i -= 2)
l[i] = std::max(l[i], l[i + 2] - 2);//同理
for (register int i = 1; i < n; i += 2)
if (l[i] && r[i])//保证两边都有
ans = std::max(ans, l[i] + r[i]);
printf("%d", ans);
}