给出一个字符串,求所有子串中能分成前后两个部分都是回文串最长的子串的长度.
在回文自动机里纪录每个点往前最远的匹配点,正来一次,反来一次.枚举分割点.
manacher也可以做:枚举每隔点作为中点时,若此刻的中点的最右端比之前存储的一个中点最右端更远,则更新超过部分所有的点的匹配点(类似于单调队列,只保存当前情况下的最优中点).
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
using namespace std;
#define MAXN 100100
#define MAXK 26
#define palin(x, id, c) (s[id - 1 - l[x]] - 'a' == c)
#define MOD 1000000007
#define LL long long
char str1[MAXN], str2[MAXN];
int p1[MAXN], p2[MAXN];
struct Trie
{
int next[MAXN][MAXK], fail[MAXN], l[MAXN];
int sz, ro, re, last;
void Init(char *s)
{
sz = 0;
ro = ++sz, l[ro] = -1, fail[ro] = ro;
memset(next[sz], 0, sizeof(next[sz]));
re = ++sz, l[re] = 0, fail[re] = ro;
memset(next[sz], 0, sizeof(next[sz]));
last = ro;
s[0] = '$';
}
void Add(char *s, int c, int id, int p[])
{
while(!palin(last, id, c)) last = fail[last];
if (next[last][c]) last = next[last][c];
else
{
int x = last;
++sz;
memset(next[sz], 0, sizeof(next[sz]));
next[x][c] = sz, l[sz] = l[x] + 2;
if (x == ro) fail[sz] = re;
else
{
x = fail[x];
while(!palin(x, id, c)) x = fail[x];
fail[sz] = next[x][c];
}
last = sz;
}
p[id] = id - l[last] + 1;
}
}pt;
int main()
{
while(gets(str1 + 1))
{
int len = strlen(str1 + 1);
for(int i = 1; i <= len; i++) str2[len - i + 1] = str1[i];
pt.Init(str1);
for(int i = 1; i <= len; i++) pt.Add(str1, str1[i] - 'a', i, p1);
pt.Init(str2);
for(int i = 1; i <= len; i++) pt.Add(str2, str2[i] - 'a', i, p2);
int ans = 2;
for(int i = 1; i < len; i++)
{
int len1 = i - p1[i] + 1;
int len2 = (len - i) - p2[len - i] + 1;
ans = max(ans, len1 + len2);
}
printf("%d\n", ans);
}
return 0;
}