集训内容总结 day3:字符串

其实是数据结构。

SAM 入门推荐读物:https://www.cnblogs.com/zaza-zt/p/15419181.html

AC 自动机

GYM103409H

\(S[0,2^k-1]=S[0,2^{k-1}-1]+S[0,2^{k-1}-1]^{-1}\)

可以把一个大区间拆成个若干长度为二整数次幂的小区间。这样有 \(O(n\log n)\) 个完整区间。不同的区间只有 \(\log\) 个。

在 AC 自动机上一段段跑,\(d_{u,k,1/-1}\) 表示 \(u\)\(S[0,2^k-1]^{1/-1}\) 到了哪里。然后还要记每个点过了多少次,记 \(f_{u,k,1/-1}\) 表示这段共走了多少次,直接按 \(k\) 往下传即可。

P5310

考虑 \(b_i=\sum_{j<i}[a_j>a_i]\) 来刻画这个关系。

建 AC 自动机,跳 fail 时只需 check 一段区间内有多少个数比 \(x\) 大就能判断这个 fail 是否可以成为后缀。

CF1801G

考虑 ACAM 先前缀和一下右节点小于某个值的匹配。这样只有 \(l<ql\le r\) 的点被额外算了。那么我们就需要找出有多少对 \([l,ql-1]\)\([ql,r]\) 匹配。

\([l,ql-1]\) 看作 \([1,ql-1]\) 不断跳 fail,\([ql,r]\) 先建出反串的 ACAM 然后从 \([ql,qr]\) 对应节点跳 fail。找 \([ql,qr]\) 可以倍增。

然后变成找两棵树上匹配的点对,可以直接做。

QOJ7742

SA 和 SAM

QOJ5312 改

\(O(n^2)\)\(O(nk)\) 直接暴力 dp 即可。

将 dp 丢到二维平面上,发现一条 \(f_{x+i,y+i}\) 关于 \(i\) 是单调的,而总共有 \(k\) 条这样的斜线。记 \(g_{i,j}\) 表示第 \(i\) 条斜线使得 \(f\) 值为 \(j\) 的第一个位置。这样状态就是 \(O(k^2)\) 了。

如何转移?发现考虑当前是什么操作,然后操作后序列需要查 \(s,t\) 的某个后缀的最长公共前缀即可。复杂度 \(O(k^2+n\log n)\)

UOJ395

P4482

等价于求 \(LCS([1,i],[1,r])\ge i-l+1\)\(i\)。考虑变成在 SAM 上求 \(a_i,a_r\)\(len(lca(a_i,a_r))\)

直接跳父亲显然倒闭,可以考虑树剖。分成两类贡献:轻子树和链上的点和这条链末端的子树。原因是轻子树的大小之和为 \(O(n\log n)\)。对于子树的部分直接线段树合并。

CF1098F

QOJ11105

P6292

\(r\) 扫描线,维护所有 \(ans(l,r)\) 的答案。从 \(r-1\to r\),每次只有长度大于某个值的点才会新被加入。

对于某个等价类找出最近的 endpos,贡献就是区间加等差数列。

设法把所有最近 endpos 相同的等价类一起做贡献。每个点都记录最近的 endpos,相同的看成一个重链。相当于找所有到根路径上的重链贡献答案,然后 access。用 LCT 维护即可。

CF104491E

QOJ6507

先跑 toposort 找出每个点代表区间长度。记 \(a(l,r)\) 表示 \(l,r\) 指向哪个点。找出 \(a(l,r)\) 可以分析 \(a(l-1,r),a(l,r+1)\) 得出。这样是 \(O(|ans|^2)\) 的。

优化不会了。

posted @ 2025-08-04 17:27  UniGravity_qwq  阅读(17)  评论(0)    收藏  举报