N : [算法竞赛进阶指南]Palindrome
Time Limit:2 Sec Memory Limit:128 MiB
Back Submit Edit
Description
[poj 3974]
如果一个字符串正着读和倒着读是一样的,则称它是回文的。
给定一个长度为N的字符串S,求他的最长回文子串的长度是多少。
Input
输入将包含最多30个测试用例,每个测试用例占一行,以最多1000000个小写字符的形式给出。
输入以一个以字符串“END”(不包括引号)开头的行表示输入终止。
Output
对于输入中的每个测试用例,输出测试用例编号和最大回文子串的长度(参考样例格式)。
每个输出占一行。
Sample Input
abcbabcbabcba
abacacbaaaab
END
Sample Output
Case 1: 13
Case 2: 6
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
using ull=unsigned long long;
const int maxn=2000010;
const int P=13331;
ull hl[maxn],hr[maxn],hp[maxn];//hl和hr分别是正序和逆序保存字符串哈希值的数组
char str[maxn],str2[maxn];//str2为字符串预处理之后的数组
ull HL(int pos,int r)
{//用于在正序中获得pos到pos+r之间的哈希值
return hl[pos+r]-hl[pos]*hp[r];
}
ull HR(int pos,int r)
{//用于在逆序中获得pos-r到pos之间的哈希值
return hr[pos-r]-hr[pos]*hp[r];
}
int main(){
//freopen("qwe.txt","r",stdin);
int t=0;
while(scanf("%s",str+1),strcmp(str+1,"END"))
{
cout<<"Case "<<++t<<": ";
int n=strlen(str+1);
int cur=1;
str2[1]='#';
for(int i=1;i<=n;i++)
{//对字符串进行预处理
str2[++cur]=str[i];
str2[++cur]='#';
}
n=cur;
hl[0]=0;
hp[0]=1;
for(int i=1;i<=n;i++)
{//构建正序字符串哈希表
hl[i]=hl[i-1]*P+(str2[i]-'a'+1);
hp[i]=hp[i-1]*P;
}
hr[n+1]=0;
for(int i=n;i>=1;i--)
{//构建逆序字符串哈希值
//注意逆序字符串哈希值是从字符串结尾开始循环计算式的
hr[i]=hr[i+1]*P+(str2[i]-'a'+1);
}
int r=1;
for(int i=1;i<=n;i++)
{
if(i-r<0||i+r>n)break;//越界时表示已经在上次循环计算中得到最大的对称字符串
if(HL(i,r)!=HR(i,r))continue;
//用于判断正序逆序的哈希值是否相同
while(str2[i-r-1]==str2[i+r+1]&&i+r+1<=n&&i-r-1>=1)
r++;//在有上句判断的基础上本语句是在扩充对称字符串范围的作用
}
cout<<r<<endl;
}
return 0;
}