RiverSheepSHEEP

后缀自动机

奔跑的心634·2022-09-20 16:06·14 次阅读

后缀自动机

后缀自动机

简介#

给定一个字符串S,我们把S的每一个后缀都插入trie中。这样这个trie就能处理许多的问题,但这颗trie的大小是O(n2)级别的,所以我们要用到后缀自动机。

构建#

定义endpos(s)为字串s在原串S中出现的位置。那不同endpos(s)的个数为O(n)级别的,我们可以将一个点看成一个endpos(s)的等价类来构建。

推荐博客:史上最通俗的后缀自动机详解

P3804 【模板】后缀自动机 (SAM)#

考虑建出parenttree,那么点u出现的次数就为u的儿子出现次数之和,但对于一个前缀的贡献是独立的,所以只要在建SAM时,对每一个前缀加一,求和即可。

CodeCodeCodeCode#

Copy
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 1e6 + 5; int n,b[N << 2],cnt,h[N << 2]; char s[N]; struct SAM{int fa,len,ch[26];}a[N << 2]; int tot = 1,pre = 1; void insam(int x) { int u = pre,v; pre = v = ++tot; a[v].len = a[u].len + 1, b[v]++; for (; u && !a[u].ch[x]; u = a[u].fa) a[u].ch[x] = v; if (!u) a[v].fa = 1; else { int g = a[u].ch[x]; if (a[g].len == a[u].len + 1) a[v].fa = g; else { int now = ++tot; a[now] = a[g], a[now].len = a[u].len + 1; a[v].fa = a[g].fa = now; for (; u && a[u].ch[x] == g; u = a[u].fa) a[u].ch[x] = now; } } } struct edge{int to,nxt;}e[N << 2]; void add(int x,int y){e[++cnt] = edge{y,h[x]},h[x] = cnt;} void dfs(int u) { for (int i = h[u]; i; i = e[i].nxt) dfs(e[i].to),b[u] += b[e[i].to]; } int main() { scanf("%s",s + 1),n = strlen(s + 1); for (int i = 1; i <= n; i++) insam(s[i] - 'a'); for (int i = 2; i <= tot; i++) add(a[i].fa,i); dfs(1); int ans = 0; for (int i = 2; i <= tot; i++) if (b[i] > 1) ans = max(ans,a[i].len * b[i]); printf("%d\n",ans); }
posted @   RiverSheep  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示
目录