[国家集训队]最长双回文串
题意
求长度(n)的串(S)的最长双回文串(T)
即(T)能分为两部分(X,Y) ((|X| geq 1,|Y| geq 1)) 且(X,Y)都为回文串
分析
可以用回文自动机维护每个位置的最长回文后缀(R[i])
那么答案就是(max(R[i] + L[i + 1]))
求(L[i])只需要翻转(S)再求一遍即可
代码
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define eps 1e-9
#define db long double
#define equals(a,b) fabs(a-b) < eps
using namespace std;
typedef long long ll;
inline ll rd(){
ll x;
scanf("%lld",&x);
return x;
}
const int maxn = 1e5 + 5;
char ss[maxn];
int L[maxn],R[maxn];
namespace pam {
int sz, tot, last;
int cnt[maxn], ch[maxn][26], len[maxn], fail[maxn];
int R[maxn]; //rightmost len
char s[maxn];
inline int node(int l) {
sz++;
memset(ch[sz], 0, sizeof(ch[sz]));
len[sz] = l;
fail[sz] = cnt[sz] = 0;
return sz;
}
inline void clear() {
sz = -1;
last = 0;
s[tot = 0] = '$';
node(0);
node(-1);
fail[0] = 1;
}
inline int getfail(int x) {
while (s[tot - len[x] - 1] != s[tot]) x = fail[x];
return x;
}
inline void insert(char c,int idx) {
s[++tot] = c;
int now = getfail(last);
if (!ch[now][c - 'a']) {
int x = node(len[now] + 2);
fail[x] = ch[getfail(fail[now])][c - 'a'];
ch[now][c - 'a'] = x;
R[idx] = len[now] + 2;
}
else R[idx] = len[now] + 2;
last = ch[now][c - 'a'];
cnt[last]++;
}
}
int main(){
scanf("%s",ss + 1);
int len = strlen(ss + 1);
pam::clear();
for(int i = 1;i <= len;i++)
pam::insert(ss[i],i);
int ans = 0;
for(int i = 1;i <= len;i++){
R[i] = pam::R[i];
}
pam::clear();
reverse(ss + 1,ss + len + 1);
for(int i = 1;i <= len;i++)
pam::insert(ss[i],i);
for(int i = 1;i <= len;i++){
L[len - i + 1] = pam::R[i];
}
for(int i = 1;i < len;i++){
ans = max(ans,R[i] + L[i + 1]);
}
cout << ans;
}