Link
BZOJ - https://www.lydsy.com/JudgeOnline/problem.php?id=2565
Luogu - https://www.luogu.org/problemnew/show/P4555
题意:求最长的两个回文串拼起来
那么
Manacher 跑一遍回文串
然后做一个递推。记录每个位置作为回文串右端能对应到最左端的回文串,作为左端同理。
……怎么实现?简单的想法是对于每个回文串右端标记左端,左端标记右端
可惜这是错的。样例都过不去惹。
实际上加一步求 max 就可以辣?
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<ctime>
#include<cctype>
using namespace std;
#define R register
const int MAXN = 2e5 + 5;
int n, Rad[MAXN], Ans;
string S;
int Llen[MAXN], Rlen[MAXN];
void Manacher()
{
for (R int Right = -1, Mid = -1, Tmp = -1, i = 0; i < n; ++i)
{
if (Right <= i)
{
while ((i + Rad[i] < n - 1) && (i - Rad[i] > 0) && (S[i - Rad[i] - 1] == S[i + Rad[i] + 1])) ++Rad[i];
Right = i + Rad[i];
Mid = i;
}
else
{
Tmp = i + Rad[(Mid << 1) - i - Rad[i]];
if (Tmp > Right)
{
Rad[i] = Right - i;
}
else
{
Rad[i] = Tmp - i;
if (Tmp == Right)
{
while ((i + Rad[i] < n - 1) && (i - Rad[i] > 0) && (S[i - Rad[i] - 1] == S[i + Rad[i] + 1])) ++Rad[i];
Right = i + Rad[i];
Mid = i;
}
}
}
Llen[i + Rad[i]] = max(Llen[i + Rad[i]], Rad[i]);
Rlen[i - Rad[i]] = max(Rlen[i - Rad[i]], Rad[i]);
}
for (R int i = 2; i < n; ++i) Rlen[i] = max(Rlen[i], Rlen[i - 2] - 2);
for (R int i = n - 3; i >= 0; --i) Llen[i] = max(Llen[i], Llen[i + 2] - 2);
for (R int i = 0; i < n; ++i) if (Llen[i] && Rlen[i]) Ans = max(Ans, Llen[i] + Rlen[i]);
}
int main()
{
cin >> S;
n = S.size();
S.reserve((n<<1)|1);
for (R int i = n - 1; i >= 0; --i)
{
S[i << 1 | 1] = S[i];
S[i << 1] = '#';
}
n <<= 1;
++n;
S[n-1] = '#';
Manacher();
cout << Ans;
return 0;
}