2565: 最长双回文串
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2579 Solved: 1316
[ Submit][ Status][ Discuss]
Description
顺序和逆序读起来完全一样的串叫做回文串。比如
acbca
是回文串,而
abc
不是(
abc
的顺序为
“abc”
,逆序为
“cba”
,不相同)。
输入长度为 n 的串 S ,求 S 的最长双回文子串 T, 即可将 T 分为两部分 X , Y ,( |X|,|Y|≥1 )且 X 和 Y 都是回文串。
输入长度为 n 的串 S ,求 S 的最长双回文子串 T, 即可将 T 分为两部分 X , Y ,( |X|,|Y|≥1 )且 X 和 Y 都是回文串。
Input
一行由小写英文字母组成的字符串S。
Output
一行一个整数,表示最长双回文子串的长度。
Sample Input
baacaabbacabb
Sample Output
12
HINT
样例说明
从第二个字符开始的字符串aacaabbacabb可分为aacaa与bbacabb两部分,且两者都是回文串。
对于100%的数据,2≤|S|≤10^5
2015.4.25新加数据一组
Source
。。。怎么评价这个非常傻X的题目呢
这题其实就是一个manacher,记f[i]为以i结尾的最长回文串,跑一遍manacher,然后直接找就好啦
但是蒟蒻一开始不会manacher。。。。
于是蒟蒻YY了一个做法
先把字符串正着反着hash一下,然后枚举每个字符,二分它能向左/向右延伸的最大长度,记录下它的最长左端点和右端点
显然对于一个回文串的左端点,要使双回文串最长,肯定是要找到一个能够包含它的、中心对称点最远的回文串
那么要怎么找呢。。。。。
蒟蒻非常的傻X。。连ST都懒得打直接上了线段树。。。(事实上用ST会更快233)
manacher大概在bzoj上跑了60ms,线段树3S。。。。。。。。。
真菜啊。。。。
代码(manacher):
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn = 200100;
char s[maxn],a[maxn];
int n,p[maxn],f[maxn];
inline LL getint()
{
LL ret = 0,f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
ret = ret * 10 + c - '0',c = getchar();
return ret * f;
}
int main()
{
scanf("%s",a + 1); n = strlen(a + 1);
n = 2 * n + 1;
for (int i = 1; i <= n; i++)
{
if (i & 1) s[i] = '#';
else s[i] = a[i / 2];
}
s[0] = '$';
int mx = 0,pos = 0;
for (int i = 1; i <= n; i++)
{
if (i <= mx) p[i] = min(mx - i + 1,p[2 * pos - i]);
else p[i] = 1;
while (s[i + p[i]] == s[i - p[i]])
{
f[i + p[i]] = max(f[i + p[i]],p[i] + 1);
p[i]++;
}
if (p[i] + i - 1 > mx) mx = i + p[i] - 1 , pos = i;
}
int ans = 0;
for (int i = 1; i <= n; i++) ans = max(ans,p[i] + f[i - p[i]] - 1);
printf("%d",ans);
return 0;
}