标签:编号 long 一个个 case char s string 子串 stream name
如果一个字符串正着读和倒着读是一样的,则称它是回文的。
给定一个长度为N的字符串S,求他的最长回文子串的长度是多少。
输入格式
输入将包含最多30个测试用例,每个测试用例占一行,以最多1000000个小写字符的形式给出。
输入以一个以字符串“END”(不包括引号)开头的行表示输入终止。
输出格式
对于输入中的每个测试用例,输出测试用例编号和最大回文子串的长度(参考样例格式)。
每个输出占一行。
输入样例:
abcbabcbabcba
abacacbaaaab
END
输出样例:
Case 1: 13
Case 2: 6
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<cstring>
using namespace std;
const int N = 10000010;
const int bace = 131;
unsigned long long hl[N], hr[N], p[N];
char s[N];
unsigned long long get(unsigned long long h[], int l, int r)
{
return h[r] - h[l - 1] * p[r - l + 1];
}
int main()
{
p[0] = 1;
int T = 1;
while (cin>>s+1, strcmp(s + 1, "END"))
{
int n = strlen(s + 1);
for (int i = n * 2; i > 0; i -= 2)//在每个字符中检查入一个数大于'z',这样好计算,就都变成了奇数个字符
{
s[i] = s[i / 2];
s[i - 1] = 'z' + 1;
}
n *= 2;
for (int i = 1, j = n; i <= n; i++, j--)//求出字符串循序和逆序的哈希值
{
hl[i] = hl[i - 1] * bace + (s[i] - 'a' + 1);
hr[i] = hr[i - 1] * bace + (s[j] - 'a' + 1);
p[i] = p[i - 1] * bace;
}
int ans = 0;
for (int i = 1; i <= n; i++)//枚举1~n的字符,找到一个个数mid,使得以这个字符为中心,半径为mid的一串字符串是最长的回文字符串 形如i-mid~i~i+mid,
{
int l = 0, r = min(i - 1, n - i);
while (l < r)//找到mid
{
int mid = l + r + 1 >> 1;
if (get(hl, i - mid, i - 1) != get(hr, n - (i + mid) + 1, n - (i + 1) + 1))//计算i左边到i-mid的字符串哈希值,是不是等于i字符右边到i+mid的哈希值,为啥是n-(i+mid)+1,n-(i+1)+1呢,因为hr数组计算的就是反过来以后的哈希值,1对应的是n,x对应的就是n-x+1,
r = mid - 1;
else
l = mid;
}
if (s[i - l] <= 'z')如果i-mid的这个数是字母,就把mid+1,你可能会问不用乘以二么,其实上面就已经是乘上2
得了
ans = max(ans, l + 1);
else//如果不是字母,就正常输出
ans = max(ans, l);
}
printf("Case %d: %d\n", T++, ans);
}
return 0;
}
标签:编号 long 一个个 case char s string 子串 stream name
原文地址:https://www.cnblogs.com/arbor-one/p/12272348.html