D2 - Prefix-Suffix Palindrome (Hard version)
题意
给你一个字符串S,找出最长的满足以下条件的字符串T:长度不超过∣S∣T为回文字符串存在两个字符串a和b(可能为空),T=prea+sufb
思路
预处理+manacher
若s串首尾字符相同,那么我们可以直接去除不影响答案。
故先从两边取对称的前后缀,之后再取余下字符串较长的回文前缀或后缀。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const ll maxn = 3e6 + 5;
char s[maxn],a[maxn],b[maxn];
int p[maxn];
int ansid;
void manacher(int n){
int m=0,mx=0,id=0;
s[++m]='$';
s[++m]='#';
for(int i=1;i<=n;i++){
s[++m]=a[i];
s[++m]='#';
}
s[++m]='%';
ansid=0;
for(int i=3;i<m;i++){
p[i]=mx>i?min(p[id*2-i],mx-i):1;
while(s[i+p[i]]==s[i-p[i]]) ++p[i];
if(i+p[i]>mx) mx=i+p[i],id=i;
if(i+p[i]-1>=2*n+1 || i-p[i]+1<=3){//如果为前缀和后缀那边所在的最大回文串则记录ansid以便于后续输出
if(p[i]>p[ansid]) ansid=i;
}
}
for(int i=ansid-p[ansid]+1;i<=ansid+p[ansid]-1;i++){
if(isalpha(s[i])) cout<<s[i];
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int T;cin>>T;
while(T--){
cin>>b+1;
int L=1,R=strlen(b+1),len=0;
while(len+1<=R/2 && b[L+len]==b[R-len]) len++;
for(int i=1;i<=len;i++) cout<<b[i];
int cnt=0;
for(int i=len+1;i<=R-len;i++) a[++cnt]=b[i];
manacher(cnt);
for(int i=len;i>=1;i--) cout<<b[i];cout<<'\n';
}
return 0;
}