题解:P10915 [蓝桥杯 2024 国 B] 最长回文前后缀
字符串哈希 + 二分 + 贪心
第一步贪心:考虑到可以删去某一段子串,且对于一段长度
那么问题就转化为在
第二步贪心:令
那么可以分类讨论,先讨论删除前缀的情况,再讨论删除后缀的情况,最后取最大值。
以删除前缀时为例,删除后缀同理:
考虑枚举删除前缀的长度
假设当前二分的长度为
代码如下:
#define rep(x,y,z) for(int x=y;x<=z;x++)
typedef unsigned long long ULL;
const int N=5e5+5,P=13331;
int n;
char tmp[N],s[N],t[N];
ULL hs[N],ht[N],p[N];
void calc(ULL h[],char *s){
p[0]=1;
int len=strlen(s+1);
rep(i,1,len){
h[i]=h[i-1]*P+s[i];
p[i]=p[i-1]*P;
}
}
ULL getstr(ULL h[],int l,int r){
return h[r]-h[l-1]*p[r-l+1];
}
void solve(){
scanf("%s",tmp+1);
int n=strlen(tmp+1);
int L=1,R=n;
while(tmp[L]==tmp[R] && L<=R) L++,R--;
if(L>R) return cout<<n/2,void();
int cnt=0;
rep(i,L,R) s[++cnt]=tmp[i];
rep(i,1,cnt) t[i]=s[i];
reverse(t+1,t+1+cnt);
calc(hs,s);
calc(ht,t);
int ans=0;
rep(i,1,cnt-1){ // 删除前缀
int l=0,r=(cnt-i)/2;
while(l<r){
int mid=(l+r+1)>>1;
if(getstr(hs,i+1,i+mid)==getstr(ht,1,mid)) l=mid;
else r=mid-1;
}
ans=max(ans,l);
}
rep(i,1,cnt-1){ // 删除后缀
int l=0,r=(cnt-i)/2;
while(l<r){
int mid=(l+r+1)>>1;
if(getstr(ht,i+1,i+mid)==getstr(hs,1,mid)) l=mid;
else r=mid-1;
}
ans=max(ans,l);
}
cout<<ans+(L-1);
}