bzoj2342: [Shoi2011]双倍回文
Description
Input
输入分为两行,第一行为一个整数,表示字符串的长度,第二行有个连续的小写的英文字符,表示字符串的内容。
Output
输出文件只有一行,即:输入数据中字符串的最长双倍回文子串的长度,如果双倍回文子串不存在,则输出0。
Sample Input
16
ggabaabaabaaball
Sample Output
12
HINT
N<=500000
分析
我们先不考虑奇数。以一个节点为中心的双倍回文。
这个节点的左边回文串和右边回文串要一模一样。
我们可以用回文自动机简单地处理出一个节点往左的最长回文串。
对于一个节点往右的最长回文串,我们可以把整串倒过来再插入回文自动机。假设i正着插入对应回文自动机上的节点为in[i],倒着插入为out[i]
我们考虑回文自动机fail树上的一条路径,每一条路径上的所有节点都是以i为结尾的一个回文字符串。
考虑这个节点左右回文串一模一样,左右回文串在回文自动机上表示同一个节点。
所以就是in[i]和out[i]再fail树上的lca
最后考虑必须是偶数长度的回文串,我们只要在做自动机的时候记录某个节点在fail树上祖先中距离它最近的偶数回文串即可。
注意回文自动机上节点有0
代码
/**************************************************************
Problem: 2342
User: 2014lvzelong
Language: C++
Result: Accepted
Time:1168 ms
Memory:106708 kb
****************************************************************/
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
const int N = 1e6 + 1e3;
long long ans;
int len[N], f[N], a[N], val[N], F[N], pos[N], last, sz, n, L;
map<int, int>ch[N];
int siz[N], to[N], pre[N], nxt[N], son[N], de[N], d[N], top;
void add(int u, int v) {to[++top] = v; nxt[top] = pre[u]; pre[u] = top;}
void dfs(int u) {
de[u] = de[f[u]] + 1; siz[u] = 1; son[u] = -1;
for(int i = pre[u]; i; i = nxt[i]) {
dfs(to[i]);
siz[u] += siz[to[i]];
if(!(~son[u]) || siz[to[i]] > siz[son[u]]) son[u] = to[i];
}
}
void dfs(int u, int chain) {
d[u] = chain; if(!(~son[u])) return;
dfs(son[u], chain);
for(int i = pre[u]; i; i = nxt[i])
if(to[i] != son[u])
dfs(to[i], to[i]);
}
int lca(int u, int v) {
for(;d[u] != d[v]; u = f[d[u]])
if(de[d[u]] < de[d[v]]) swap(u, v);
return de[u] > de[v] ? v : u;
}
void PDT_pre() {
f[last = sz = 0] = 1; add(1, 0);
len[++sz] = a[n = 0] = F[1] = F[0] = -1;
}
void Extend(int n, int c) {
int p, np, x;
for(p = last;a[n - len[p] - 1] != a[n];p = f[p]) ;
if(!ch[p][c]) {
len[np = ++sz] = len[p] + 2;
for(x = f[p]; a[n - len[x] - 1] != a[n]; x = f[x]) ;
f[np] = ch[x][c]; ch[p][c] = np;
F[np] = len[np] & 1 ? F[f[np]] : np;
add(f[np], np);
}
pos[n] = last = ch[p][c];
}
void work() {
char ch = getchar();
while(ch < 'a' || ch > 'z') ch = getchar();
for(;ch >= 'a' && ch <= 'z'; ch = getchar()) a[++n] = ch - 'a';
a[n + 1] = 26; a[n + 2] = 27; L = n + 1 << 1;
for(int i = 1;i <= n; ++i) a[L - i + 1] = a[i];
for(int i = 1;i <= L; ++i) Extend(i, a[i]);
}
int main() {
int ans = 0; PDT_pre(); work();
dfs(1); dfs(1, 1);
for(int i = 1;i <= n; ++i) {
int x = lca(pos[i], pos[L - i]);
if(F[x] != -1) ans = max(ans, (len[F[x]] << 1));
}
printf("%d\n", ans);
return 0;
}