0
点赞
收藏
分享

微信扫一扫

Acwing 139. 回文子串的最大长度(前缀+后缀处理+哈希+二分)

眸晓 2022-09-26 阅读 118

地址:​​https://www.acwing.com/problem/content/141/​​

Acwing 139. 回文子串的最大长度(前缀+后缀处理+哈希+二分)_逆序

解析:

1:在假设完全无差错的情况下,不同子串对应不同哈希值。

对于abcba,那么ab的哈希值应该等于ba的反转哈希值。

也就是说,根据一个字符串,迅速求出它的逆序字符串的反哈希值,如果两者相等,则两者为正逆序的关系。

所以要处理两个哈希,一个前缀哈希和一个后缀哈希。

2:每次处理一个串,它分两种情况,长度为偶数和奇数,很明显,奇数的时候,我们只需要根据中点 ,就可以直接判断以它为中点的两个半径是否相等。而偶数相对麻烦一点,所以考虑把字符串括一下,每两个字符之间加入同一个26个字母之外的一个字符('z'+1即可),这样,我们枚举所有包含原字母的串,它们都是奇数长度。(一个非常好的技巧~)

3:枚举每一个中点,二分半径,即可在O(nlogn)的复杂度下ac了。

#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<stack>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e6+10,P=131;//131 or 13331¾­ÑéÖµ
ull hl[2*maxn],hr[2*maxn],p[2*maxn];
int le;
char st[2*maxn];
void init()
{
p[0]=1;
for(int i=1;i<=le;i++)//正缀
{
p[i]=p[i-1]*P;
hl[i]=hl[i-1]*P+st[i]-'a'+1;
}
for(int i=le;i>=1;i--)//后缀
{
hr[i]=hr[i+1]*P+st[i]-'a'+1;
}
}
ull checkl(int l,int r)
{
return hl[r]-hl[l-1]*p[r-l+1];
}
ull checkr(int l,int r)
{
return hr[l]-hr[r+1]*p[r-l+1];//因为与正缀求法是相反的。
}
int main()
{
int ac=1;
while(scanf("%s",st+1))
{
if(!strcmp(st+1,"END"))
break;
le=strlen(st+1);
for(int i=2*le;i>=1;i-=2)//扩充
{
st[i]=st[i/2];
st[i-1]='z'+1;
}
le=2*le;
init();
int maxx=0;
for(int i=1;i<=le;i++)
{
int l=0 ,r=min(i-1,le-i);//最大半径
while(l<r)
{
int md = l+r+1>>1;
if(checkl(i-md,i-1)!=checkr(i+1,i+md))//如果不相等,则半径值大了,r=md-1让它变小。
{
r=md-1;
}
else
l=md;
}
int ml=l*2+1;
if(st[i+l+1]=='{'||i+l+1>le)  //根据尾部+1处判断实际长度,这个举个例子就可以推出
ml=ml-ml/2;
else
ml=ml-ml/2-1;
maxx=max(maxx,ml);
}
printf("Case %d: %d\n",ac++,maxx);
}
}



举报

相关推荐

0 条评论