P4555 题解
P4555 [国家集训队] 最长双回文串 题解
补一个题解区没有的做法。
记字符串长度为
首先可以用 Manacher 预处理出以每个点为中心的最长回文串,左右端点分别记为
代码部分:
#include <bits/stdc++.h>
using namespace std;
string s;
int len, ans, p[200005], tree[200005], L[200005], R[200005];
int lowbit(int x)
{
return x & -x;
}
void update(int u, int x)
{
while (u <= len)
{
tree[u] = max(tree[u], x);
u += lowbit(u);
}
}
int query(int u)
{
int res = 0;
while (u > 0)
{
res = max(res, tree[u]);
u -= lowbit(u);
}
return res;
}
int main()
{
cin >> s;
len = s.size();
s = '$' + s;
s = s + s;
for (int i = len; i >= 1; i--)
s[2 * i] = s[i];
for (int i = 1; i <= len * 2 + 1; i += 2)
s[i] = '#';
len = 2 * len + 1;
for (int t = 1, mid = 0, r = 0; t <= len; t++)
{
if (t <= r) p[t] = min(p[mid * 2 - t], r - t + 1);
while (s[t - p[t]] == s[t + p[t]]) p[t]++;
if (t + p[t] > r)
{
r = t + p[t] - 1;
mid = t;
}
}
for (int i = 1; i <= len; i++)
{
if (s[i] == '#') L[i] = len - query(len - i + 1) + 1;
int r = i + p[i] - 1;
update(len - r + 1, len - i + 1);
}
for (int i = 1; i <= len; i++)
tree[i] = 0;
for (int i = len; i >= 1; i--)
{
if (s[i] == '#') R[i] = query(i);
int l = i - p[i] + 1;
update(l, i);
}
for (int i = 1; i <= len; i++)
if (s[i] == '#') ans = max(ans, R[i] - L[i]);
cout << ans << endl;
return 0;
}