CF1326 D2 - Prefix-Suffix Palindrome (Hard version) manacher

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
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;
}

你可能感兴趣的:(codeforces,manacher,字符串)