题意:
给定一个字符串s。
求一个最长回文子串t=a+b (a是s的前缀,b是s的后缀)
解析:
首先遍历前后缀相同的一部分,如果没有剩余一段,那么整个串就是最长回文子串
如果有剩余的一段为[l,r],就对[l,r]这段跑马拉车 求出这部分最大前缀回文或最大后缀回文即可 设为x
最长回文子串就为: [0,l]+x+[r+1,n]
#include<bits/stdc++.h>
#define Min(a,b) a>b?b:a
using namespace std;
const int N=2e6+10000;
char s[N],str[N];
int p[N];
int len,n,f;
int ans;
int t;
void init(int l,int r)
{
int k=0;
str[k++]='@';
for(int i=l;i<=r;i++)
{
str[k++]='#';
str[k++]=s[i];
}
str[k++]='#';
len=k;
str[k]='\0';
}
void mlc()
{
int mx=0,id=0;
p[0]=0;
for(int i=1;i<len;i++)
{
if(i<mx) p[i]=min(mx-i,p[2*id-i]);
else p[i]=1;
while(str[i-p[i]]==str[i+p[i]]) p[i]++;
if(i+p[i]>mx)
{
mx=i+p[i];
id=i;
}
if(p[i]==i)
{
if(ans<p[i])
{
ans=p[i]-1;
f=1;
}
}
if(p[i]+i==len)
{
if(ans<p[i])
{
ans=p[i]-1;
f=2;
}
}
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
f=0;
ans=0;
scanf("%s",s);
n=strlen(s);
int l=0,r=n-1;
while(s[l]==s[r]&&l<r)//去除相同的前缀和后缀
{
l++;
r--;
}
if(l>=r)
{
cout<<s<<endl;
continue;
}
init(l,r);
mlc();
for(int i=0;i<l;i++) printf("%c",s[i]);
if(f==1) //输出[l,r]这一段的最长回文前缀部分
{
for(int i=l,j=0;j<ans;i++,j++) printf("%c",s[i]);
}
else//输出[l,r]这一段的最长回文后缀部分
{
for(int i=r-ans+1;i<=r;i++) printf("%c",s[i]);
}
//输出剩下的一段
for(int i=r+1;i<n;i++) printf("%c",s[i]);
puts("");
}
}