[国家集训队]最长双回文串(马拉车)

传送门

题意

输入长度为n的串s,求s的最长双回文子串t,即t可分为两部分x和y且x和y都是回文串。

题解

考虑枚举中间的断点,所以我们只要记录以i为开头的最长回文串和以i为结尾的最长回文串。

通过中心和长度求开头已经在 这篇 里面讲过了,这里不再赘述。结尾也只需自己慢漫推一推也可出来。

可是以某个位置为开头的最长回文串不一定是某个中心的最长回文串的开头,其实它还有可能是某个中心的最长回文串的一部分。

我们只需令第i个位置的值和第i-1个位置的值-2比较取最大即可。

同理以某个位置为结束的最长回文串也类似。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 const int N = 200010;
 6 int n, n0, id, mx;
 7 int p[N];
 8 char s[N], a[N];
 9 int l[N], r[N], ans;
10 int main() {
11     scanf("%s", s + 1);
12     n = strlen(s + 1);
13     n0 = 0;
14     a[++n0] = '$';
15     for (int i = 1; i <= n; i++) a[++n0] = '#', a[++n0] = s[i];
16     a[++n0] = '#';
17     id = mx = 0;
18     for (int i = 1; i <= n0; i++) {
19         p[i] = mx > i ? min(mx - i, p[id * 2 - i]) : 1;
20         while (a[i + p[i]] == a[i - p[i]]) ++p[i];
21         if (mx < i + p[i]) mx = i + p[i], id = i;
22         l[(i - p[i]) / 2 + 1] = max(l[(i - p[i]) / 2 + 1], p[i] - 1);
23         r[(i - p[i]) / 2 + p[i] - 1] = max(r[(i - p[i]) / 2 + p[i] - 1], p[i] - 1);
24     }
25     for (int i = 2; i <= n; i++) {
26         l[i] = max(l[i], l[i - 1] - 2);
27     }
28     for (int i = n - 1; i >= 1; i--) {
29         r[i] = max(r[i], r[i + 1] - 2);
30     }
31     for (int i = 1; i < n; i++) {
32         ans = max(ans, l[i + 1] + r[i]);
33     }
34     cout << ans;
35     return 0;
36 }

猜你喜欢

转载自www.cnblogs.com/zcr-blog/p/12558185.html