题目链接
https://codeforces.com/contest/1326/problem/D2
题意
给你一个字符串\(S\),找出最长的满足以下条件的字符串\(T\):
- 长度不超过\(S\)
- \(T\)为回文字符串
- 存在两个字符串\(a\)和\(b\)(可能为空),\(T=a+b\)(\(a\)为\(S\)的前缀,\(b\)为\(S\)的后缀)
思路
假设\(a\),\(b\)有一个为空时,我们直接对整个\(S\)跑一遍\(manacher\),求出最长回文前缀和最长回文后缀,两者取最大。
假设\(a\),\(b\)不为空,我们先对\(S\)进行首尾匹配,当匹配到不相同时,就截取剩下中间的那段字符串\(c\),跟上面一样,对\(c\)跑一遍\(manacher\),求出最长回文前缀和最长回文后缀并两者取最大,然后合并起来就是结果了。
最后输出求出来的这两个字符串的长度最大的一个就好了
#include<bits/stdc++.h> using namespace std; const int maxx = 3e6+10; char tmp[maxx]; int len[maxx]; int s1,s2; void Manacher(string s) { tmp[0]='$'; tmp[1]='#'; int t=s.size(); for(int i=0;i<2*t+5;i++)len[i]=0; for(int i=1;i<=t;i++) { tmp[2*i]=s[i-1]; tmp[2*i+1]='#'; } tmp[2*t+2]='\0'; int mx=0; int mid; for(int i=1;tmp[i];i++) { if(i<mx)len[i]=min(len[2*mid-i],mx-i); else len[i]=1; while(tmp[i-len[i]]==tmp[i+len[i]])len[i]++; if(len[i]+i>mx) { mx=len[i]+i; mid=i; } int l=len[i]-1; if(i%2==0) { l=(l-1)/2; int p=i/2; if(p-l==1)s1=max(s1,len[i]-1); if(p+l==t)s2=max(s2,len[i]-1); } else { l=l/2; int p=(i-1)/2,q=(i+1)/2; if(p-l+1==1)s1=max(s1,len[i]-1); if(q+l-1==t)s2=max(s2,len[i]-1); } } } int main() { int T; scanf("%d",&T); while(T--) { s1=0,s2=0; string s,ans1,ans2; cin>>s; int n=s.size(); Manacher(s); if(s1>s2)ans1=s.substr(0,s1); else ans1=s.substr(n-s2); int i=0,j=n-1; while(i<j&&s[i]==s[j])ans2+=s[i],i++,j--; string ss=s; if(i<j) { s1=0,s2=0; ss=s.substr(i,j-i+1); int n=ss.size(); Manacher(ss); if(s1>s2)ans2+=ss.substr(0,s1); else ans2+=ss.substr(n-s2); } ans2+=s.substr(j+1); if(ans1.size()>=ans2.size())cout<<ans1<<endl; else cout<<ans2<<endl; } return 0; }
来源:https://www.cnblogs.com/HooYing/p/12531165.html