【字符串哈希】回文子串的最大长度

传送门

题意

给定一个串,求最长的回文子串

数据范围

题解

一个判定是不是回文串可以用一个长度表示回文半径
枚举每一个点,假设当前点是 i
每次都检查奇数长度和偶数长度
奇数情况下分为 \(\{ i-len , i-1 \}\)\(\{ i +1 , i+len\}\)
子回文串长度就是\(2 \times len + 1\)
偶数情况下分为\(\{ i-len , i-1 \}\)\(\{ i , i+len-1 \}\)

遍历每一个点,然后二分回文半径的长度
二分的时候
最小长度应该是0
奇数长度的时候,最大长度应该是开始到当前点前一个点,和当前点后一个点到结尾这两个长度的最小值
偶数长度是当前点前一个点,和当前到最后的最小值

Code

#include <bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int N=1e6+10,P=131;
char s[N];
int m;
int t;
ull h1[N],h2[N],p[N];
ull geth1(int l,int r){
	return h1[r]-(h1[l-1]*p[r-l+1]);
}
ull geth2(int l,int r){
	return h2[l]-h2[r+1]*p[r-l+1];
}
int main(){
	p[0]=1;
	for(int i=1;i<=N;i++) p[i]=p[i-1]*P;

	while(scanf("%s",s+1) && strcmp(s+1,"END")){
		cout<<"Case "<<++t<<": ";
		 int ans=0,len=strlen(s+1);
		 h2[len+1]=0;
		 for(int i=1;i<=len;i++) h1[i]=h1[i-1]*P+(s[i]-'a'+1);
		 for(int i=len;i;i--) h2[i]=h2[i+1]*P+(s[i]-'a'+1);

		 for(int i=1;i<=len;i++){
		 	int l=0,r=min(i-1,len-i);//二分的是长度,即到左边和到右边长度的最大值
		 	while(l < r){
		 		int mid=l+r+1>>1;
		 		if(geth1(i-mid,i-1) == geth2(i+1,i+mid))
		 			l=mid;
		 		else
		 			r=mid-1;
		 	}
		 	ans=max(ans,l*2+1);

		 	l=0,r=min(i-1,len-i+1); //当前点算右半边所以要+1

		 	while(l<r){
		 		int mid=l+r+1>>1;
		 		if(geth1(i-mid,i-1) == geth2(i,i+mid-1))
		 			l=mid;
		 		else
		 			r=mid-1;
		 	}
		 	ans=max(ans,l*2);
		 }
		 cout<<ans<<endl;
	}

}
posted @ 2021-09-23 14:04  Hyx'  阅读(88)  评论(0编辑  收藏  举报