luoguP4555 [国家集训队]最长双回文串 manacher算法
不算很难的一道题吧....
很容易想到枚举断点,之后需要处理出以$i$为开头的最长回文串的长度和以$i$为结尾的最长回文串的长度
分别记为$L[i]$和$R[i]$
由于求$R[i]$相当于把$L[i]$反过来求一遍,因此只需考虑求$L[i]$
考虑$manacher$算法
我们注意到,当$mr$扩展时,第一个把$mr$扩展到$i$的中心$j$构成的串就是$L[i]$
在$manacher$算法中统计一下即可
复杂度$O(n)$
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ri register int #define rep(io, st, ed) for(ri io = st; io <= ed; io ++) #define drep(io, ed, st) for(ri io = ed; io >= st; io --) const int sid = 2e5 + 1e4; char s[sid], t[sid]; int n, m, r[sid], L[sid], R[sid]; void manacher(char *s, int *lst, int opt) { r[1] = 1; lst[1] = 1; int mr = 1, pos = 1; rep(i, 2, m) { r[i] = min(mr - i + 1, r[pos + pos - i]); while(i - r[i] > 0 && s[i + r[i]] == s[i - r[i]]) lst[i + r[i]] = 2 * r[i] + 1, r[i] ++; if(i + r[i] - 1 > mr) mr = i + r[i] - 1, pos = i; } if(opt) reverse(lst + 1, lst + m + 1); } int main() { scanf("%s", s + 1); n = strlen(s + 1); rep(i, 1, n) t[++ m] = '#', t[++ m] = s[i]; t[++ m] = '#'; reverse(t + 1, t + m + 1); manacher(t, R, 1); reverse(t + 1, t + m + 1); manacher(t, L, 0); int ans = 0; rep(i, 1, m) if(t[i] == '#') ans = max(ans, (L[i] + R[i] - 1) / 2); printf("%d\n", ans); return 0; }
喵喵喵?喵喵喵! 喵喵喵......