【字符串】回文树学习笔记
燃鹅,一年后的我在想,回文树是个什么东西?(._."||)
2020-10-08
好好理解了回文树。
理解后的感觉:为啥子之前会觉得很复杂?Orz
根据自己理解改了个自己能看懂的模板
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+50; int last,tot,n; int nex[maxn][27],len[maxn],fail[maxn],s[maxn],cnt[maxn]; /* n 是字符串的长度 last 是当前节点的上一节点 记录信息的节点编号从1开始 next[i][j] 是 i节点左右添加字符x后所形成的新的字符串的 节点标号 len[i] 是i节点所代表的字符串的长度 fail[i] 是节点i的最长回文后缀的 节点标号 s[i] 是字符串的第i个字符 cnt[i] 是i节点所代表的的回文串在整个字符串里出现的次数 */ inline void init() { s[0]=-1;fail[0]=1;last=0; len[0]=0;len[1]=-1;tot=1; } /* 零号节点的最长回文后缀是指向1号节点 而1号节点的长度是 len[1]=-1; 这个操作有利于: 当添加第一个字符时(节点2) 新的回文串长度 恰好等于:-1+2=1 */ inline int getfail(int x,int id) { while(s[id-len[x]-1]!=s[id])x=fail[x]; return x; } /* 从x节点往下找 找回文后缀恰好回文后缀的前一个字符等于要添加的字符 使得能构成一个新的回文后缀 若找不到,则结果是回到1号节点 然后再添加新字符 则形成了一个长度为1的回文串 len[1]=-1有利于 在找不到的情况下 最后一定能找到1号节点满足: (s[id-len[1]-1]=s[id-(-1)-1])==s[id] */ inline int newnode(int x) { len[++tot]=x; return tot; } inline int solve() { int i,p,q=1; init(); for(i=1;i<=n;i++) { p=getfail(last,i); //找到上一节点可以添加s[i]字符的回文后缀所在的节点标号 p if(nex[p][s[i]]==0)//如果 p节点没有过两边添加s[i]的记录 { printf("%d %d ",i,q); q=newnode(len[p]+2);//新字符串为p串两边添加s[i] fail[q]=nex[getfail(fail[p],i)][s[i]]; //q的最长回文后缀是 p的满足前一个字符是s[i]的回文后缀再加字符s[i]的回文串所在节点 没有则为节点0 nex[p][s[i]]=q; for(int j=i-len[q]+1;j<=i;j++)printf("%c",s[j]+'a'); putchar(10); } last=nex[p][s[i]];//将当前节点更新到上一节点 cnt[nex[p][s[i]]]++;//这个回文串出现的记录+1 } for(i=tot;i>1;i--) { cnt[fail[i]]+=cnt[i]; /* i节点出现必是包含其回文后缀的出现 所以最后需要更新回文后缀出现的次数 因为之前更新的节点所代表的串 都不会是别的串的最长回文后缀 */ } } int main() { char s1[maxn]; scanf("%s",s1); n=strlen(s1); for(int i=1;i<=n;i++)s[i]=s1[i-1]-'a'; solve(); }
2019-09-10 22:39:54
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=3e5+50; char ss[maxn]; int last,tot,n; int nex[maxn][27],len[maxn],fail[maxn],s[maxn],cnt[maxn]; inline void init() { n=strlen(ss); for(int i=1;i<=n;i++)s[i]=ss[i-1]-'a'; s[0]=-1;fail[0]=1;last=0; len[0]=0;len[1]=-1;tot=1; } inline int getfail(int x,int id) { while(s[id-len[x]-1]!=s[id])x=fail[x]; return x; } inline int newnode(int x) { len[++tot]=x; return tot; } inline void PT() { int p,q=1; init(); for(int i=1;i<=n;i++) { p=getfail(last,i); if(nex[p][s[i]]==0) { // printf("%d %d ",i,q); q=newnode(len[p]+2); fail[q]=nex[getfail(fail[p],i)][s[i]]; nex[p][s[i]]=q; // for(int j=i-len[q]+1;j<=i;j++)printf("%c",s[j]+'a');putchar(10); } last=nex[p][s[i]]; cnt[nex[p][s[i]]]++; } for(int i=tot;i>1;i--)cnt[fail[i]]+=cnt[i]; } inline int solve() { ll ans=0; PT(); for(int i=1;i<=tot;i++)ans=max(ans,(ll)len[i]*cnt[i]); printf("%lld\n",ans); } int main() { scanf("%s",ss); solve(); }