题意:
给出一个字符串 S S S,求 S S S的最长双回文子串 T T T,即可将 T T T分为两部分 X X X, Y Y Y, ( ∣ X ∣ , ∣ Y ∣ ≥ 1 ) (|X|,|Y|≥1) (∣X∣,∣Y∣≥1) 且 X X X和 Y Y Y都是回文串。
题解:
我们知道
l
e
n
[
i
]
len[i]
len[i]表示以
i
i
i这个字符结束的最长回文串的长度,然后我们只需要建立两个回文自动机(一个正向一个反向)就可以啦!
详细细节见代码!
A C AC AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int MAXN = 5e5+50;
struct Palind{
int nxt[MAXN][26],fail[MAXN],len[MAXN],cnt[MAXN];
char str[MAXN];
int sz,lst,sn;
void Init(){
fail[0] = fail[1] = 1;
len[0] = 0,len[1] = -1;
sz = lst = 1;
sn = 0;
str[0] = '#';
}
int Insert(char ch){
str[++sn] = ch;
int root = lst;
while(str[sn]!=str[sn-len[root]-1]) root = fail[root];
if(!nxt[root][ch-'a']){
len[++sz] = len[root] + 2;
int tmp = fail[root];
while(str[sn]!=str[sn-len[tmp]-1]) tmp = fail[tmp];
fail[sz] = nxt[tmp][ch-'a'];
nxt[root][ch-'a'] = sz;
}
lst = nxt[root][ch-'a'];
return len[lst];
}
}PAM1,PAM2;
char s[MAXN];
int lx[MAXN],ly[MAXN];
int main(){
scanf("%s",s+1);
int len = strlen(s+1);
PAM1.Init(),PAM2.Init();
for(int i=1;i<=len;i++) lx[i] = PAM1.Insert(s[i]);
for(int i=len;i>=1;i--) ly[i] = PAM2.Insert(s[i]);
int res = 0;
for(int i=1;i<=len-1;i++)
res = max(res,lx[i]+ly[i+1]);
//用原串来解释,lx[i]就是以i为结束的回文串的长度,可以看作向左进行拓展的最长长度
//ly[i+1]就是以i+1为结束的回文串的长度,看作向右拓展的最长长度
cout<<res<<endl;
}