D2 - Prefix-Suffix Palindrome (Hard version)

题意

S T S T a b T = p r e a + s u f b 给你一个字符串S,找出最长的满足以下条件的字符串T:\\ 长度不超过|S|\\ T为回文字符串\\ 存在两个字符串a和b(可能为空),T=pre_a+suf_b STSTabT=prea+sufb

思路

+ m a n a c h e r 预处理 + manacher +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;
}