P4555 [国家集训队]最长双回文串 回文树(回文自动机)简单题
贴个题目链接:https://www.luogu.org/problem/P4555
题目:输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(∣X∣,∣Y∣≥1)且X和Y都是回文串。
输入输出样例
输入 #1
baacaabbacabb
输出 #1
12
说明/提示
【样例说明】
从第二个字符开始的字符串aacaabbacabb
可分为aacaa
与bbacabb
两部分,且两者都是回文串。
思路,我们的回文自动机每次加进去一个字符都会更新last,last就是以这个字符为结尾能得到的最长回文串的节点号,那我们直接开个ans数组记录一下len【last】就是表示以这个字符为结尾的最长回文串长度。
搞两个回文树,一个正着跑,一个倒着跑,那么我们就可以ans1【i】+ans2【i+1】表示的意思就是以s【i】为X结尾,s【i+1】为Y开头(因为这个是倒着跑的,正着看就是以它为开头)最回文大长度。
#include <bits/stdc++.h> #define met(a, b) memset(a, b, sizeof(a)) #define ll long long #define ull unsigned long long using namespace std; const int maxn = 100005; const int N = 26; struct PAM{ int ne[maxn][N];//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成 int fail[maxn];//fail指针,失配后跳转到fail指针指向的节点 int cnt[maxn]; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的) int num[maxn]; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数 int len[maxn];//len[i]表示节点i表示的回文串的长度(一个节点表示一个回文串) int S[maxn] ;//存放添加的字符 int last ;//指向新添加一个字母后所形成的最长回文串表示的节点。 int n;//表示添加的字符个数。 int p;//表示添加的节点个数。 int ans[maxn];//以st【i】为结尾的最长回文子串的长度 int newnode(int l){ //新建节点 for(int i = 0; i < N; i++) ne[p][i] = 0; cnt[p] = num[p] = 0; len[p] = l; return p++; } void init(){ //初始化 p = 0; newnode(0); newnode(-1);//顺序不能反 last = 0; n = 0; S[n] = -1; //防止越界 fail[0] = 1; } int get_fail(int x){ while(S[n - len[x] - 1] != S[n]) x = fail[x]; return x; } void add(int c){ c = c - 'a'; S[++n] = c; int cur = get_fail(last);//通过上一个回文串找这个回文串的匹配位置 if(!ne[cur][c]){//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串 int now = newnode(len[cur] + 2);//新建节点 fail[now] = ne[get_fail(fail[cur])][c];//和AC自动机一样建立fail指针,以便失配后跳转 ne[cur][c] = now; num[now] = num[fail[now]] + 1; } last = ne[cur][c]; ans[n] = len[last]; cnt[last]++; } void count_cnt(){ for(int i = p-1; i >= 0; i--){ cnt[fail[i]] += cnt[i]; //父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串! } } }pam1, pam2; char st[maxn]; int arr[10005]; int main(){ scanf("%s",st); pam1.init(); pam2.init(); int len = strlen(st); for(int i = 0; i < len; i++) pam1.add((int)st[i]); for(int i = len-1; i >= 0; i--) pam2.add((int)st[i]); pam1.count_cnt(); pam2.count_cnt(); int ma = 0; for(int i = 1; i < len; i++){ ma = max(ma, pam1.ans[i] + pam2.ans[len-i]); } cout << ma << endl; return 0; }