题目链接:点击查看
题目大意:给出一个字符串 s ,求最长双回文子串,题目规定最长双回文子串 t 可以拆成左右两部分,满足两部分都是回文串
题目分析:一开始读错题了,以为是双回文串本身也需要是回文串,结果发现并不是,这样的话直接用回文自动机求就好了,其中有个参数len数组正好代表了以某个点为结尾的最长回文后缀的长度,正着跑一遍维护一个最长回文后缀的长度,然后再倒着跑一遍维护答案就好了
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
char s[N];
int suf[N];
struct Palindrome_tree
{
int nxt[N][26];
int fail[N]; // 当前节点最长回文后缀的节点
int len[N]; // 当前节点表示的回文串的长度
int cnt[N]; // 当前节点回文串的个数, 在getcnt后可得到全部
int sed[N]; // 以当前节点为后缀的回文串的个数(并不是表示第i结尾的回文串的种类数,如果要求每个点结尾的数的回文串个数,得用last)
int record[N]; //record记录了节点回文串的结束位置
char s[N];
int tot; // 节点个数
int last; // 上一个节点
int n;//当前字符串的长度
void init()
{
tot = n = 0;
memset(fail, 0, sizeof fail);
memset(cnt, 0, sizeof cnt);
memset(sed, 0, sizeof sed);
memset(len, 0, sizeof len);
memset(nxt, 0, sizeof nxt);
}
void build()
{
len[0] = 0, len[1] = -1; // 0为偶数长度根, 1为奇数长度根
tot = 1, last = 0;
fail[0] = 1;
}
int getfail(int x, int n)
{
while (s[n - len[x] - 1] != s[n]||n-len[x]-1<0) // 比较x节点回文串新建两端是否相等
//n-len[x]-1<0这个是我自己加的,多组的时候光第一个条件是不够的,所以有错请手动删除
x = fail[x]; // 若不同, 再比较x后缀回文串两端
return x;
}
void insert(char ch)
{
int c = ch - 'a';//全小写要用a 全大写要用A 不然会错
s[++n]=ch;
int p = getfail(last, n);// 得到第i个字符可以加到哪个节点的两端形成回文串
if (!nxt[p][c])
{
tot++;
len[tot] = len[p] + 2; // 在p节点两端添加两个字符
fail[tot] = nxt[getfail(fail[p], n)][c]; //tot点的后缀回文,可以由上一个节点的后缀回文尝试得到
sed[tot] = sed[fail[tot]] + 1; // 以当前节点为结尾的回文串个数
nxt[p][c] = tot; // 新建节点
}
last = nxt[p][c]; // 当前节点成为上一个节点
cnt[last]++; //当前节点回文串++
record[last] = n;
}
void get_cnt()
{
for (int i = tot; i > 0; i--)
cnt[fail[i]] += cnt[i];
//fail[i] 的节点 为 i 节点的后缀回文串, 所以个数相加
}
}tree;
int main()
{
// freopen("input.txt","r",stdin);
// ios::sync_with_stdio(false);
scanf("%s",s);
int n=strlen(s);
tree.init();
tree.build();
for(int i=0;i<n;i++)
{
tree.insert(s[i]);
suf[i]=tree.len[tree.last];
}
tree.init();
tree.build();
int ans=0;
for(int i=n-1;i>=1;i--)
{
tree.insert(s[i]);
ans=max(ans,suf[i-1]+tree.len[tree.last]);
}
printf("%d\n",ans);
return 0;
}