对原串前缀和后缀作一个01标记pre[i],suf[i]表示1-i和i-n能否能形成回文。记以i为中心的回文半径为r(i)。
这些都可以在O(N)时间内求出。也可以使用Hash+二分等方法O(NlogN)内求出。
我们考虑中间一个回文串的位置,只要考虑其前缀回文串的长度,后缀回文串的长度,在判断中间剩余的是否是回文串。
#include<bits/stdc++.h>
using namespace std;
const int maxn=40101;
int pre[maxn],suf[maxn];
int p[maxn];
char str[maxn],s[maxn];
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%s",str+1);
int len=strlen(str+1);
memset(pre,0,sizeof(pre));
memset(suf,0,sizeof(suf));
for(int i=1;i<=len+1;i++){ //15-32行为manacher算法
s[i*2]=str[i];
s[i*2-1]='#';
}
s[0]='*';
memset(p,0,sizeof(p));
int id=0;
for(int i=1;i<=len*2;i++){
if(p[id]+id>i)
p[i]=min(p[2*id-i],p[id]+id-i);
else
p[i]=1;
while(s[i-p[i]]==s[i+p[i]])
++p[i];
if(p[i]+i>p[id]+id)
id=i;
}
for(int i=1;i<=2*len;i++){ //判断前缀,分奇偶脑补
if(p[i]-i==0){
pre[(i-1)*2]=1;
}
if(p[i]+i-1==len*2+1){ //判断后缀,分奇偶脑补
if((i-p[i]+1)%2==1)
suf[i-p[i]+2]=1;
else
suf[i-p[i]+1]=1;
}
}
int flag=0;
for(int i=1;i<=len;i++){
if(flag==1)
break;
if(pre[i*2]==1){ //前缀存在回文
for(int j=len;j>i+1;j--)
if(suf[j*2]==1){ //后缀存在回文
int mid=i+j;
if(p[mid]>=j-i){
flag=1;
break;
}
}
}
}
if(flag==1)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}