[笔记] 后缀自动机 (SAM)

实现#

void ins(int c){
	int np = ++dcnt, p = lst; lst = np;
	t[np].len = t[p].len + 1, t[np].eps = 1;
	while(p && !t[p].ch[c]) t[p].ch[c] = np, p = t[p].fa;
	if(!p) t[np].fa = 1;
	else{
		int q = t[p].ch[c];
		if(t[q].len == t[p].len + 1) t[np].fa = q;
		else{
			int nq = ++dcnt; t[nq].len = t[p].len + 1;
			t[nq].fa = t[q].fa, memcpy(t[nq].ch, t[q].ch, sizeof t[q].ch);
			while(p && t[p].ch[c] == q) t[p].ch[c] = nq, p = t[p].fa;
			t[q].fa = t[np].fa = nq;
		}
	}
}

应用#

检查字符串是否出现#

直接在 SAM 上转移即可。

不同子串个数#

  • SAM 是个 DAG,所以可以在上面 DP。

    一般来说,DAG上可能重复转移,很难跑计数 DP 的,但是 SAM 有一个性质是 : 任意两个节点的表示集合没有交。

    所以从任何一个节点出发的路径组成的串,都是互不相同的,那么只要统计路径数,不需要考虑重复问题。

  • SAM 每个节点表示的串没有交集,而且一定表示了所有的串。那么把所有节点表示的串的个数加起来就好了,而每个节点表示的个数,也就是 endpos 的大小,就是 maxlen(u)-maxlen(fa).

线段树合并维护 endpos#

SAM 的每个节点的 endpos 集合是所有 fa 为这个节点的节点 endpos 集合的并,于是可以线段树合并得到一个节点的 endpos 集合。

习题
  • CF1037H Security
posted @   IrisT  阅读(76)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
主题色彩