题目大意
给你多个字符串,要你求各字符串的最长回文子串的长度。
一行一个字符串,以一行END结束。
解
字符串哈希。
分析题目:回文串就是串的前半部分,和后半部分倒过来完全相同的串。
我们可以分别从前往后处理,从后往前处理,得出正着和倒着的哈希值。
然后枚举回文中心,二分回文长度,比较枚举出的串的前半部分和后半部分的哈希值。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#define ull unsigned long long //大大大大大!!自然溢出吧!!
using namespace std;
int l, r, mid, t, len, ans;
ull c[1000050], z[1000050], f[1000050];
char s[1000050]; //读入串,它比字符串快
void work() {
memset(z, 0, sizeof(z));
memset(f, 0, sizeof(f));
ans = 1; //一个字母
for (int i = 0; i < len; ++i) z[i + 1] = z[i] * 131 + s[i]; //正着
for (int i = len; i > 0; --i) f[i] = f[i + 1] * 131 + s[i - 1]; //反着
for (int i = 1; i <= len; ++i) {
//枚举中心
l = 0;
r = (len >> 1) + 1;
while (r >= l) {
//奇数长度回文
mid = (l + r) >> 1;
if (i - mid <= 0 || i + mid > len)
r = mid - 1;
else if (z[i] - z[i - mid - 1] * c[mid + 1] == f[i] - f[i + mid + 1] * c[mid + 1]) {
//前串与后串对比
//类似前缀和的,后减(前挪位后的值)=需取串的哈希值
ans = max(ans, mid * 2 + 1);
l = mid + 1;
} else
r = mid - 1;
}
l = 0;
r = (len >> 1) + 1;
if (z[i] - z[i - 1] * 131 == f[i + 1] - f[i + 2] * 131)
ans = max(ans, 2);
while (r >= l) {
//偶数长度回文
mid = (l + r) >> 1;
if (mid == 0)
break;
if (i - mid + 1 <= 0 || i + mid > len)
r = mid - 1;
else if (z[i] - z[i - mid] * c[mid] == f[i + 1] - f[i + mid + 1] * c[mid]) {
//前串与后串对比
ans = max(ans, mid * 2);
l = mid + 1;
} else
r = mid - 1;
}
}
printf("Case %d: %d\n", t, ans); //输出
}
int main() {
char cc;
c[0] = 1;
for (int i = 1; i <= 1000000; ++i) c[i] = c[i - 1] * 131;
cc = getchar(); //输入串
len = 0;
while (cc != ' ' && cc != '\n') {
s[len] = cc;
cc = getchar();
++len;
}
t = 1;
while (s[0] != 'E') {
//结束
work();
++t;
cc = getchar();
len = 0;
while (cc != ' ' && cc != '\n') {
s[len] = cc;
if (cc >= 'A' && cc <= 'Z')
return 0;
cc = getchar();
++len;
}
}
}