[国家集训队]最长双回文串
[国家集训队]最长双回文串
题目描述
顺序和逆序读起来完全一样的串叫做回文串。比如acbca
是回文串,而abc
不是(abc
的顺序为abc
,逆序为cba
,不相同)。
输入长度为nnn的串SSS,求SSS的最长双回文子串TTT,即可将TTT分为两部分XXX,YYY,(∣X∣,∣Y∣≥1|X|,|Y|≥1∣X∣,∣Y∣≥1)且XXX和YYY都是回文串。
输入输出格式
输入格式:一行由小写英文字母组成的字符串SSS。
输出格式:一行一个整数,表示最长双回文子串的长度。
输入输出样例
输入样例#1:
baacaabbacabb
输出样例#1:
12
说明
【样例说明】
从第二个字符开始的字符串aacaabbacabb
可分为aacaa
与bbacabb
两部分,且两者都是回文串。
对于100%的数据,2≤∣S∣≤1052≤|S|≤10^52≤∣S∣≤105
分析
qwq,刚学Manacher呀,hw记录的是到i为止可以扩展的最长回文子序列,题目求的是,双回文(很高大上的样子,qaq)。我们就可以用l,r数组记录下来,到i为止,向左向右可以扩展的最长回文,这样r[i]-l[i]不就是一个包含两个回文子串的字串了吗,qwq。。。
#include <cstdio> #include <cmath> #include <deque> #include <stack> #include <queue> #include <cmath> #include <cstring> #include <algorithm> #include <iostream> using namespace std; #define ll long long #define ull unsigned long long const int Maxn=1000001; const int inf=2147483647; int n,m; char a[Maxn],s[Maxn]; int hw[Maxn],l[Maxn],R[Maxn]; int main() { cin>>a; n=strlen(a); s[0]=s[1]='#'; for(int i=0; i<n; i++) { s[i*2+2]=a[i]; s[i*2+3]='#'; } n=n*2+2; s[n]=0; int r=0,mid=0; for(int i=0; i<n; i++) { if(i<r) hw[i]=min(hw[mid-(i-mid)],hw[mid]-(i-mid)); else hw[i]=1; while(s[i+hw[i]]==s[i-hw[i]]) ++hw[i]; if(i+hw[i]>r) { r=hw[i]+i; mid=i; } } int top=0; for(int i=0; i<n; i++) while(top<=i+hw[i]-1) l[top++]=i; top=n-1; for(int i=n-1; i>=0; i--) while(top>=i-hw[i]+1) R[top--]=i; int ans=0; for(int i=0; i<n; i++) ans=max(ans,R[i]-l[i]); cout<<ans<<endl; return 0; }