如果一个字符串正着读和倒着读是一样的,则称它是回文的。
给定一个长度为N的字符串S,求他的最长回文子串的长度是多少。
输入格式
输入将包含最多30个测试用例,每个测试用例占一行,以最多1000000个小写字符的形式给出。
输入以一个以字符串“END”(不包括引号)开头的行表示输入终止。
输出格式
对于输入中的每个测试用例,输出测试用例编号和最大回文子串的长度(参考样例格式)。
每个输出占一行。
输入样例:
abcbabcbabcba
abacacbaaaab
END
输出样例:
Case 1: 13
Case 2: 6
思路:
先分别从头至尾,从尾到头哈希一次
枚举回文串中心和长度,将回文串分成前后两半,再判断两半是否构成回文
倒着的哈希:
对于一个长度为l的字符串a(下标从1开始)
Hash[a] = a[1]*pl-1 + a[2]*pl-2 + … + a[l]*p0
TLE
一个个加长度的…
#include <iostream>
#include <cstdio>
using namespace std;
#define N 1000005
unsigned long long P=131;
unsigned long long Hash1[N],Hash2[N],p[N];
unsigned long long cal1(int l,int r)
{
return Hash1[r]-Hash1[l-1]*p[r-l+1];
}
unsigned long long cal2(int l,int r)
{
return Hash2[l]-Hash2[r+1]*p[r-l+1];
}
int main(){
p[0]=1;
for(int i=1;i<=1000000;++i)
{
p[i]=p[i-1]*P;
}
string s;
int t=0,ans;
while(cin>>s && s!="END")
{
int m=s.size();
Hash1[0]=0;
ans=1;
for(int i=1;i<=m;++i)
{
Hash1[i]=P*Hash1[i-1]+(s[i-1]-'a'+1);
}
Hash2[m+1]=0;
for(int i=m;i>0;--i)
{
Hash2[i]=P*Hash2[i+1]+(s[i-1]-'a'+1);
}
for(int i=1;i<=m;++i)//枚举以s[i]为中心的 长度为奇数的回文串
{
int p=1;//向左右拓展的长度
while(1)
{
if(cal1(i-p,i)==cal2(i,i+p) && i-p>0 && i+p<=m)
p++;
else
break;
}
p--;
ans=max(ans,2*p+1);
}
for(int i=1;i<m;++i)//枚举以s[i]和s[i+1]之间的缝隙为中心的 长度为偶数的回文串
{
int p=1;
while(1)
{
if(cal1(i-p+1,i)==cal2(i+1,i+p) && i-p+1>0 && i+p<=m)
p++;
else
break;
}
p--;
ans=max(ans,2*p);
}
t++;
printf("Case %d: %d\n",t,ans);
}
return 0;
}
AC
二分枚举长度,很多细节要注意(WA了N次…)
#include <iostream>
#include <cstdio>
using namespace std;
#define N 1000005
unsigned long long P=131;
unsigned long long Hash1[N],Hash2[N],p[N];
unsigned long long cal1(int l,int r)
{
return Hash1[r]-Hash1[l-1]*p[r-l+1];
}
unsigned long long cal2(int l,int r)
{
return Hash2[l]-Hash2[r+1]*p[r-l+1];
}
int main(){
p[0]=1;
for(int i=1;i<=1000000;++i)
{
p[i]=p[i-1]*P;
}
string s;
int t=0,ans;
while(cin>>s && s!="END")
{
int m=s.size();
Hash1[0]=0;
ans=1;
for(int i=1;i<=m;++i)
{
Hash1[i]=P*Hash1[i-1]+(s[i-1]-'a'+1);
}
Hash2[m+1]=0;
for(int i=m;i>0;--i)
{
Hash2[i]=P*Hash2[i+1]+(s[i-1]-'a'+1);
}
for(int i=2;i<m;++i)//枚举以s[i-1]为中心的 长度为奇数的回文串
{
int l=0,r=min(i-1,m-i),p;//向左右拓展的长度
while(l<r)
{
p=(l+r+1)>>1;
if(i-p>0 && i+p<=m && cal1(i-p,i-1)==cal2(i+1,i+p))
/*printf("#1 %d %d %d %d\n",i,p,i-p,i+p),*/l=p;
else
r=p-1;
//printf("%d %d %d\n",l,r,p);
//printf("%d %d %d %d\n",i,p,i-p,i+p);
}
//printf("#1 %d %d %d %d\n",i,l,r,p);
if(!(i-p>0 && i+p<=m && cal1(i-p,i-1)==cal2(i+1,i+p)))//可能一次循环中p不满足条件但l>=r跳出了
p--;
ans=max(ans,p<<1 | 1);
}
for(int i=1;i<m;++i)//枚举以s[i-1]和s[i]之间的缝隙为中心的 长度为偶数的回文串
{
int l=0,r=min(i,m-i),p;
while(l<r)
{
p=(l+r+1)>>1;
//printf("#2 %d %d %d %d\n",i,l,r,p);
if(i-p+1>0 && i+p<=m && cal1(i-p+1,i)==cal2(i+1,i+p))
/*printf("#2 %d %d %d %d\n",i,p,i-p+1,i+p),*/l=p;
else
r=p-1;
//printf("%d %d %d %d\n",i,p,i-p+1,i+p);
}
//printf("#2 %d %d %d %d\n",i,l,r,p);
if(!(i-p+1>0 && i+p<=m && cal1(i-p+1,i)==cal2(i+1,i+p)))
p--;
ans=max(ans,l<<1);
}
t++;
printf("Case %d: %d\n",t,ans);
}
return 0;
}