顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。
思路:回文串上manacher求出每个位置的回文半径
对于每个位置i我们维护它作为某回文串起点或者终点R[i] , L[i],最长向左和向右延伸的距离,则答案为max(r[i] + l[i])
例如baacaabbacabb对于位置1,它以b为回文串baacaab起点最多往右延伸到7,作为回文串b的终点最多往左延伸到1,维护每个位置这样的延展。
因为马拉车后有特殊符号,回文半径是落在特殊符号上的所以我们最后维护每个特殊符号上的左右最长延展方便点。
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define pb push_back
#define IOS ios::sync_with_stdio(false)
//#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define all(v) v.begin(),v.end()
typedef long long ll;
const int N=1e6+10;
int p[N],r[N];
int len;
int R[N],L[N];
char s[N],s2[N];
void change()
{
s2[0]='$';
s2[1]='$';
_for(i,0,len-1)
{
s2[(i<<1)+2] = s[i];
s2[(i<<1)+3] = '$';
}
len = len * 2+1;
}
void manacher()
{
change();
int mx=0;
int mid=0;
for(int i=0 ;i<=len ;i++)
{
if( i < mx ) p[i] = min(p[2*mid-i] , mx-i);
else p[i]=1;
while( s2[i-p[i]] == s2[i+p[i]] ) p[i]++;
if( p[i] + i > mx)
{
mx = p[i] + i;
mid = i;
}
int l = i+p[i]-1;
int r = i-p[i]+1;
R[r] = max(p[i]-1,R[r]);//以r为回文串的右端点的最长回文串
L[l] = max(p[i]-1,L[l]);//以l为回文串的左端点的最长回文串
}
}
signed main()
{
// /!!!
// freopen("data.txt","r",stdin);
// !!!
IOS;
cin>>s;
len = strlen(s);
manacher();
int ans=0;
//注意跳跃间隔为2
for(int i=1 ;i<=len ;i+=2) R[i] = max(R[i] , R[i-2] -2 );//前一个右端会-2,回文串变短
for(int i=len-1 ;i>=1 ;i-=2) L[i] = max(L[i] , L[i+2] - 2 );
for(int i=1 ;i<=len;i+=2)
{
ans = max(ans , L[i] + R[i]);
}
cout<<ans<<endl;
}