题目描述
给定一个字符串, 要求求出他的最长回文子串
包含多个输入, 以END结束
样例
Sample Input
abcbabcbabcba
abacacbaaaab
END
Sample Output
Case 1: 13
Case 2: 6
思路
- 我们枚举每个字符,求以他为中心的最长回文串, 记录最长的一段,就是最终结果
- 对于回文串是偶数的情况, 我们把原串都在他们的两个字符间加入一个和原来的不相干字符,就可以在不敢变原来串的情况下,把所有情况都改变成奇数
- 枚举时我们用到二分优化
- 建立hash值时, 我们创建一个正序suml和一个倒序sumr记录字符串的hash值, 在寻找以某个点为中心的回文串时, 我们用到一个正序, 一个倒序的长度为mid的hash值, 在求倒序的时候, 需要将下标映射。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef unsigned long long ULL;
const int N = 2000010, M = 13331;
int suml[N], sumr[N], p[N];
char s[N];
ULL query(int sum[], int l, int r)
{
return sum[r] - sum[l - 1] * p[r - l + 1];
}
int main()
{
int t = 1;
p[0] = 1;
for(int i = 1; i < N; i++)
p[i] = p[i - 1] * M;
while(~scanf("%s", s + 1))
{
if(strcmp(s + 1, "END") == 0)
break;
int n = strlen(s + 1);
for(int i = n * 2 ; i > 0; i -= 2)
{
s[i] = s[i / 2];
s[i - 1] = 'z' + 1;
}
n *= 2;
for(int i = 1, j = n; i <= n; i++, j--)
{
suml[i] = suml[i - 1] * M + s[i] - 'a' + 1;
sumr[i] = sumr[i - 1] * M + s[j] - 'a' + 1;
}
int ans = 0;
for(int i = 1; i<= n; i++)
{
int l = 0, r = min(i - 1, n - i);
while(l < r)
{
int mid = (l + r + 1) >> 1;
if(query(suml, i - mid, i - 1) != query(sumr, n - (i + mid) + 1, n - (i + 1) + 1)) r = mid - 1;
else l = mid;
}
if(s[i - l] == 'z' + 1)
ans = max(ans, l);
else ans = max(ans, l + 1);
}
printf("Case %d: %d\n", t++, ans);
}
return 0;
}