如图所示 , 可以表示成上图的形式(对应位置想同颜色即为相同字母) ,而且这样表示一定是最优的(可以证明) , 所以可以先暴力枚举 S 中前后相等的部分 , 然后对剩余部分取得最长的公共前缀/后缀即可。
#include<bits/stdc++.h>usingnamespace std;#definefifirst#definesesecond#defineIOSstd::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);#defineintlonglongconstint N =2e6+10;constint mod =1e9+7;typedef pair<int,int>PII;
string s;int t , n;/*
abcdeffedcba
bc abcdeed cba
*/int d[N], pre[N], nex[N];//给出一个字符串求d[i]数组并返回马拉车串
string manacher(string s){
string now ="#$";int n = s.size();for(int i =0; i < n ; i ++) now += s[i], now +='$';
n = now.size();for(int i =0; i < n ; i ++) pre[i]= nex[i]= i;
d[1]=1;for(int i =2, l , r =1; i < n ; i ++){if(i <= r) d[i]=min(d[r - i + l], r - i +1);else d[i]=1;while(now[i - d[i]]== now[i + d[i]]){
d[i]+=1;
pre[i + d[i]-1]= i - d[i]+1;
nex[i - d[i]+1]= i + d[i]-1;}if(i + d[i]-1> r) l = i - d[i]+1, r = i + d[i]-1;}return now;}voidwatch(string s){int n = s.size();for(int i =0; i < n ; i ++) cout << s[i]<<" ";
cout <<"\n";for(int i =0; i < n ; i ++) cout << d[i]<<" ";
cout <<"\n";}signedmain(){
IOS
cin >> t;while(t --){
cin >> s;int n = s.size(), st =0;while(st < n && s[st]== s[n - st -1]&& st < n - st -1) st +=1;
string a , b , c;for(int i =0; i < st ; i ++) a += s[i];for(int i = n - st ; i < n ; i ++) b += s[i];for(int i = st ; i < n - st ; i ++) c += s[i];
string mid;if(c.size()){
string now =manacher(c);// watch(now);
n = now.size()-2;int x =((nex[2]-2+1)+1)/2;int y =((n - pre[n]+1)+1)/2;
n = c.size();if(x >= y){for(int i =0; i < x ; i ++) mid += c[i];}else{for(int i = n - y ; i < n ; i ++) mid += c[i];}}
string ans = a + mid + b;
cout << ans <<"\n";}return0;}//freopen("文件名.in","r",stdin);//freopen("文件名.out","w",stdout);