题意:
一个字符串的环,可以任意断开,使的子串的最大回文串最长,输出长度。
但是你有两次将一个字符修改成任意字符的机会。
题解:
字符串Hash
将串延长1倍,枚举回文串的中间点,看看在最多修改2次的前提下最多有多长。
具体方法:
首先二分出可以向两侧扩展的最大长度,然后跳过一个字符(意味一次修改),再二分最大长度,再跳过,再二分即可。
代码:
#include<bits/stdc++.h>
#define N 200010
#define INF 1e9
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lowwer_bound
#define eps 1e-8
#define P 1000000007
#define M 377
#define IO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
LL h1[N],h2[N],p[N];int a1,len;
char x[N];
LL spy(LL *h,int l,int r)
{
return (h[r]-h[l-1]*p[r-l+1]%P+P)%P;
}
int cal(int x,int y)
{
int l=1,r=min((len/2+x-y-1)/2,min(len-y,x-1)); int ans;
if (spy(h1,x-1,x-1)!=spy(h2,len-y,len-y)) return 0;
while(r-l>=0)
{
int t=(l+r)>>1;
if (spy(h1,x-t,x-1)==spy(h2,len-y+1-t,len-y))
{
ans=t;
l=t+1;
}else r=t-1;
}
return ans;
}
int main()
{
IO
p[0]=1;for (int i=1;i<N;i++) p[i]=p[i-1]*M%P;
int T;
cin>>T;
while(T--)
{
cin>>x+1; len=strlen(x+1); len<<=1;
for (int i=len/2+1;i<=len;i++) x[i]=x[i-len/2];
for (int i=1;i<=len;i++) h1[i]=(h1[i-1]*M+x[i])%P;
for (int i=1;i<=len;i++) h2[i]=(h2[i-1]*M+x[len-i+1])%P;
int ans=0;
for (int i=1;i<=len;i++)
{
int max_len=min(len-i,i-1);int tmp=0;
max_len=min(max_len,(len/2-1)/2);
if (max_len<=0) continue;
a1=cal(i,i);
if (max_len==a1)
{
ans=max(ans,a1);
continue;
}else tmp=a1+1;
ans=max(ans,tmp);
max_len-=tmp;
if (max_len<=0) continue;
a1=cal(i-tmp,i+tmp);
if (max_len==a1)
{
ans=max(ans,a1+tmp);
continue;
}else tmp+=a1+1;
ans=max(ans,tmp);
max_len-=tmp;
if (max_len<=0) continue;
a1=cal(i-tmp,i+tmp);
tmp+=a1;
ans=max(ans,tmp);
}
cout<<2*ans+1<<endl;
}
}