HDU3068 最长回文 <Manacher>
最长回文
Time Limit: 4000/2000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
Problem Description
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等
Input
输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000
Output
每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.
Sample Input
aaaa
abab
Sample Output
4
3
标签:Manacher
Manacher板子题。
不懂Manacher的童鞋可以戳这里:https://segmentfault.com/a/1190000003914228
简单来说,Manacher就是记录以每个位置为中心的回文串的半径长度,这样在后面计算的时候可以根据对称性,利用前面的结果加速,找更长匹配时暴力扩展,复杂度$O(n)$。由于此算法仅能对付长度为奇数的回文串(毕竟你算的是以每个点为中心的回文串),故先在每两个字符间插入一个占位符。
附上AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX_L 110000
using namespace std;
char s[MAX_L*2+5];
int f[MAX_L*2+5];
int manacher (char* s0) {
int len = strlen(s0);
for (int i = 0; i < len; i++) s[i*2+1] = '#', s[i*2+2] = s0[i];
s[len = len*2+1] = '#';
int pos = 0, r = 0, ret = 0;
for (int i = 1; i <= len; i++) {
f[i] = (i < r) ? min(f[2*pos-i], r-i) : 1;
while (i-f[i] >= 1 && i+f[i] <= len && s[i-f[i]] == s[i+f[i]]) f[i]++;
if (i+f[i] > r) pos = i, r = i+f[i];
ret = max(ret, f[i]-1);
}
return ret;
}
int main() {
char s0[MAX_L+5];
while (~scanf("%s", s0)) printf("%d\n", manacher(s0));
return 0;
}