Time Limit: 10 Sec Memory Limit: 128 MB
Description
顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为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
2012国家集训队Round 1 day2
manacher练习题。 网上都是正着跑一次再反着跑一次,那样似乎要快一点。(无所谓啦,时间那么长)
在原来的基础上记一个由当前位置开始最长的回文串长度,然后直接枚举第一个串的回文中心就好。
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 300003;
char s1[MAXN], s2[MAXN];
int len1, len2, ans;
int p[MAXN], a[MAXN];
void init() {
len1 = (int)strlen(s1);
s2[0] = '$';
s2[1] = '#';
for(int i = 0; i < len1; i++) {
s2[2 * i + 2] = s1[i];
s2[2 * i + 3] = '#';
}
len2 = 2 * len1 + 2;
s2[len2] = '%';
}
void manacher() {
int id = 0, mx = 0;
for(int i = 1; i < len2; i++) {
if(mx > i) p[i] = min(p[2 * id - i], mx - i);
else p[i] = 1;
while(s2[i - p[i]] == s2[i + p[i]]) p[i]++;
if(i + p[i] > mx) {
mx = i + p[i];
id = i;
}
}
}
int main() {
scanf("%s", s1);
init();
manacher();
memset(a, 0, sizeof(a));
for(int i = 1; i < len2; i++) {
for(int j = p[i]; j > 0; j -= 2) a[i - j + 2] = max(a[i - j + 2], j - 1);
}
ans = 0;
for(int i = 1; i < len2; i++) {
if(a[i + p[i]]) ans = max(ans, a[i + p[i]] + p[i] - 1);
}
printf("%d\n", ans);
return 0;
}