2025.7-2025.8 做题记录

2025.7-2025.8 做题记录

7.1 - 7.11

复习段考 + 段考 + 讲评课

7.12

模拟赛

7.12 T1 - 规则制定 (单调栈)

所有区间的区间和之和容易求,拆到每个元素上即可

下面考虑如何求所有区间的最大值之和

若区间内有多个最大值,考虑将贡献放到最靠前的最大值

求出 \(\text{lmax}_i\) 表示 \(i\) 前最靠后的满足 \(a_j \ge a_i\)\(j\)\(\text{rmax}_i\) 表示 \(i\) 后最靠前的满足 \(a_j > a_i\)\(j\)

\(a_i\) 作为最大值的贡献次数即为 \([\text{lmax}_i, \text{rmax}_i]\) 中长度 \(\ge 3\) 的区间个数

实现时可以用单调栈 \(O(n)\) 维护

7.12 T2 - 作文批改 (随机权 + 和 Hash)

考虑星战的做法,给字符 \(c\)随机权值 \(v_c\)和哈希判断是否相同

不过这里有个"出现次数为 \(k\) 倍",因此考虑先求出 \(t\) 的哈希值 \(B\) (不取模),\(B\) 为模数维护 \(s\) 的前缀哈希值 \(pre_i\)

此时子串 \(s_{[l, r]}\) 符合要求等价于 \(pre_r = pre_{l-1}\)

由生日悖论,值域为 \(V\) 时出现冲突的期望抽样次数为 \(O(\sqrt V)\);此处抽样次数为 \(10^7\),需保证 \(B \ge 10^{14}\)

实现细节:

  • 可以根据 \(|t|\) 动态调整随机权范围
  • umap 常数太大,直接 sort 后双指针比 umap 快

7.12 T3 - 赛道设计 (Adhoc)

可以通过手玩猜出 \(|R-L| \in [3, 5]\) 的结论 (起点也可以视作拐点)

下面给出严谨证明

设有 \(m\) 个拐点,则赛道为 \(m\) 边形,每个内角均为 \(90^{\circ}\)\(270^{\circ}\),内角和为 \((m-2) \times 180^{\circ}\)

由于所有 \(L / R\) 对应的内角只能均为 \(90^{\circ}\)\(270^{\circ}\),且两者对应度数不同,可得 (不妨设 \(L\)\(90^{\circ}\) )

\(L \times 90^{\circ} + R \times 270^{\circ} = (L+R-2) \times 180^{\circ}\)

整理即得 \(L-R = 4\)

由于连续的 \(LR / RL\) 不会带来方向上的变化,可先将其删去;调整起点,最后一定能剩下 \(LLLL / RRRR\)

这个构造是简单的;之后重新往里添加 \(LR / RL\) 的过程相当于选两个点,将路线从直线改成三折

每次重新调整其他所有点的位置可以做到相对位置不变;时间复杂度 \(O(Tn^2)\)

实现咕咕咕

LOJ6538 烷基计数 加强版 加强版 (群论 + 生成函数 + 牛迭)

见群论基础 - 学习笔记 Blog

P6597 烯烃计数 (群论 + 生成函数 + 牛迭)

见群论基础 - 学习笔记 Blog

P6598 烷烃计数 (群论 + 生成函数 + 牛迭)

见群论基础 - 学习笔记 Blog

7.13

开摆 + 补 whk

7.14

P3391 【模板】文艺平衡树

本题中,我们并不关心平衡树每个节点具体的值是否满足 BST 的性质

此处平衡树的每个节点对应原序列的下标,换句话说,我们按照下标建树

考虑如何刻画翻转操作;若我们能够分裂出 \([l, r]\) 对应的子树,将每层的节点全部左右调换即可 (可理解为值换了,对应下标不换)

直接换显然会 TLE;考虑线段树懒标记的思想,给要全部调换的子树的根打 tag,用到的时候再真正交换儿子

现在考虑如何分裂出 \([l, r]\) 对应的子树

注意到序列下标始终满足 BST 的性质,考虑按排名分裂的思想,只不过此处是按子树大小分裂;具体的:

  1. 分裂出 \([1, l-1]\)\([l, n]\) (按大小为 \(l-1\) 分裂)
  2. \([l, n]\) 分裂为 \([l, r]\)\([r+1, n]\) (按大小为 \(r-l+1\) 分裂)

P3835 【模板】可持久化平衡树

仍然套路的考虑记录每个版本的根,复制所有修改过的节点

具体的,为避免直接修改历史版本的值,在每次 split 与 merge 时对将进行分裂 / 合并的节点复制一份再操作即可

实现时,无须复制递归处理的另一侧 (递归处理子树时自然会复制的)

P5338 [TJOI2019] 甲苯先生的滚榜 (平衡树)

把 int 换成结构体,"修改通过题数和罚时"可变成先删除后插入

注意人的编号无法直接和 Treap 中的值建立联系,需要开个辅助数组

P4146 序列终结者 (平衡树 - 区间加 + 区间翻转 + 区间 max)

考虑在 Treap 上的节点维护当前下标的值 + 子树对应区间的最大值

区间翻转仍然通过打 tag 维护,区间加相当于又多了个 tag;修改时直接分裂出区间打上 tag 即可

注意,打 tag 的顺序是:

  1. 打 tag 前做好当前节点的修改
  2. 给当前节点打上 tag
  3. pushdown 时做好儿子节点的修改,把 tag 传到儿子节点上

为什么不能在 pushdown 时只做当前节点的修改,pushdown 儿子时再修改儿子?

因为 merge 时实际上非递归侧的儿子不会被 pushdown,需要在 pushdown 当前节点时就处理好儿子节点的信息

P3765 总统选举 (平衡树 + 随机化 - 带修绝对众数)

先考虑如何判断区间 \([l, r]\) 是否存在绝对众数

考虑随机化;随机 \(\text{lim}\) 次,每次随出一个位置 \(i\),判断 \(a_i\)\([l, r]\) 中出现次数是否超过一半

这样单次失败概率是 \(\displaystyle \frac{1}{2}\)\(\text{lim}\) 次就是 \(\displaystyle \frac{1}{2^\text{lim}}\),大概可以接受

那么问题在于如何快速统计 \(a_i\)\([l, r]\) 中的出现次数

先考虑不带修怎么做

对每个值 \(v\) 开 vector 记录其出现位置 (显然有序),查询时直接二分即可

带修相当于要支持删除 + 插入,二分可以变成查排名;那么对每个值 \(v\) 开一棵平衡树即可

实现时可以取 \(\text{lim} = 13\)

P2596 [ZJOI2006] 书架 (平衡树 - 下标移动)

操作 \(4\) 是根据值查排名,操作 \(5\) 是根据排名查值,明示平衡树;问题在于我们没办法直接建立编号与位置的关系

考虑给每本书赋值 \(v\) 代表其相对位置大小 (由于是相对的,没必要时刻连续)

为建立编号与 \(v\) 的联系,考虑开两个 map,第一个从编号映射到 \(v\),第二个从 \(v\) 映射到编号

接下来考虑每个操作:

  • Top,从 map 中取出编号对应的 \(v\),将 \(v\) 修改为全局编号最小值 \(-1\) 即可

    实现时可以维护全局编号最小值,"修改"就是删除 + 插入

  • Bottom,类似的,维护全局编号最大值,删除 + 插入即可

  • Insert,本质上是与前驱或后继交换;注意到 Treap 上节点对应的 \(v\) 没变,变的只有 \(v\) 与编号的对应关系

    从 map 中取出 \(v\),查出前驱 / 后继,将 map 上两组对应关系交换即可

  • Ask,从 map 中取出 \(v\),根据值查排名即可

  • Query,根据排名查值,最后通过 map 从 \(v\) 映射回编号即可

P2566 [SCOI2009] 围豆豆 (区间DP + 计算几何)

先考虑如何判断点在多边形内

由计算几何知识,考虑从点引一条射线,若与多边形交点个数为奇数则包含,反之不包含

此处多边形的边只能是水平 / 竖直的,为方便判断,钦定每个点引射线的方向都是水平向右的

因此,在平行于射线 (水平方向) 移动时不计算交点,竖直移动时才计算

设 DP 状态 \(f_{x, y, S}\) 表示走到 \((x, y)\),点的包含关系为 \(S\) 时的最短步数;其中,\(S_i\) 代表第 \(i\) 个点引出的射线与多边形交点的奇偶性

接下来考虑如何计算 \(S\)

直接按"每经过一次点右边的格子就算一次"的方式考虑是不可取的,因为每个格子有"进入"、"离开"两次操作

注意到按同一方向 (均上 \(\rightarrow\) 下 / 均下 \(\rightarrow\) 上) 只应当被算一次,因此考虑从经过格子的两个方向上统计;具体的:

  • 从上 \(\rightarrow\) 下进入格子时,统计 \(1\)

  • 从下 \(\rightarrow\) 上离开格子时,统计 \(1\)

    为什么这里是"离开"而非"进入"?因为要想形成多边形,必然要跨过格子所在水平线,只有离开格子时才是真正跨过去

实现时可以枚举起点,bfs 进行转移,第二次走到起点时结束

初始状态为 \(f_{x, y, 0} = 0\);设 \(v_S\)\(S\) 状态包含的点的价值和,答案为 \(\max (v_S-f_{x, y, S})\)

时间复杂度 \(O(n^2m^22^D)\)

7.15

P3401 洛谷树 (树剖 + 拆位)

考虑如何维护子路径 xor 和

注意到边权 \(\le 2^{10}\),考虑拆位,开 10 棵线段树

考虑经典转化,将路径 xor 变为两个根链 xor,维护每个点到根的 xor 值

\(cnt_0\)\(u, v\) 间路径中第 \(i\) 位为 \(0\) 的点的个数,\(cnt_1\)\(u, v\) 间路径中第 \(i\) 位为 \(1\) 的点的个数,贡献即为 \(cnt_0 \times cnt_1 \times 2^i\)

那么维护区间中根链 xor 当前位为 \(0\) / \(1\) 的点的个数即可

对单点改,若 \((u, v)\) 更改后边权的第 \(i\) 位与更改前不同,则相当于子树区间 \(0\) / \(1\) 翻转

综上,上树剖 + 支持区间加区间 \(0\) / \(1\) 翻转区间和的线段树即可

P2542 [AHOI2005] 航线规划 (树剖 - 删边求割边个数)

首先考察是树怎么做

显然,此时 \(u, v\) 间的割边个数即为两点树上路径中的边的个数;这启示我们给边赋 \(1\),做树剖 + 路径区间查

在树的基础上给 \(u, v\) 加边,相当于让两点树上路径中的边全部处于环中

此时这些边不再产生贡献,做路径区间推平即可

综上,上树剖 + 支持区间加区间推平区间和的线段树即可

P3676 小清新数据结构题 (树剖 + 线段树 - 区间加区间平方和)

首先考虑没有换根怎么做

先求出每个点 \(i\) 初始的子树大小 \(siz_i\),维护 \(siz_i\) 的平方和

此时单点改只会对根链上的点的子树大小产生影响,为路径区间加

显然,直接上支持区间加区间平方和的线段树即可

接着考虑换根;对于这类操作,我们一般不真换,而是分析其在保持根不动的前提下带来的变化

不妨设根换为点 \(u\)

  • 对点 \(u\) 的子树中的点 \(v\),贡献不变
  • 对点 \(u\),从 \(siz_u^2\) 变为 \((\sum siz_i)^2\)
  • 对非根链上的点 \(v\),贡献不变
  • 对根链上的点 \(v\),子树大小减少了面向 \(u\) 的部分,增加了面向根的部分

不妨设 \(1, u\) 间路径上的点为 \(1 = a_1 \rightarrow a_2 \rightarrow \cdots \rightarrow a_k = u\),点 \(i\) 原大小为 \(siz_i\),新大小为 \(siz'_i\),原答案为 \(t\),则新答案为:

\[t' = t-\sum_{i=1}^{k} siz_{a_i}^2+\sum_{i=1}^{k} (siz'_{a_i})^2 \]

显然有 \(siz'_{a_i} + siz_{a_{i+1}} = siz_1 = siz'_u\),代入,可得

\[\begin{aligned} t' &= t-siz_1^2-\sum_{i=2}^{k} siz_{a_i}^2+(siz'_k)^2+\sum_{i=1}^{k-1} (siz'_{a_i})^2 \\ &= t-(siz_1^2-(siz'_u)^2)-\sum_{i=2}^{k} siz_{a_i}^2+\sum_{i=1}^{k-1} (siz_1-siz_{a_{i+1}})^2 \\ &= t+(k-1)siz_1^2-2siz_1 \times \sum_{i=2}^{k} siz_{a_i} \end{aligned} \]

那么只需维护 \(t, siz_1\) 与根链路径区间和即可;

综上,仍然是上树剖 + 支持区间加区间和区间平方和的线段树即可

P5391 [Cnoi2019] 青染之心 (树剖 - 末尾加 / 撤销完全背包优化空间)

操作序列实际上形成了一棵树add 相当于拼个儿子,erase 相当于回退到父亲;要求所有根链的完全背包

暴力做法时空复杂度均为 \(O(qV)\),空间上无法接受;考虑如何优化

注意到若节点 \(u\) 的 DP 数组已经传到每个儿子 \(v\) 上,其本身已经没有用处了;因此考虑将某个儿子 \(v\) 的 DP 数组覆写到 \(u\) 的数组上

结合树链剖分,考虑令 \(v\)\(u\)重儿子,最后处理 \(v\),将其 DP 数组覆写到 \(u\) 的数组上

每当我们 dfs 完一条根到叶子的链时,立刻回收空间,经过的轻儿子数是 \(\log\) 的,那么空间复杂度也是 \(\log\)

P5314 [Ynoi2011] ODT (树剖 + 平衡树维护轻儿子)

"第 \(y\) 小点权"明示我们使用平衡树

考虑修改;暴力做法是把路径上所有点的平衡树全改一遍,显然无法接受

考虑与上道题类似的策略,令 \(u\) 点的平衡树维护其所有轻儿子的权值

路径改时只会经过 \(\log\) 个轻儿子,只会改 \(\log\) 个平衡树 (修改就是删除 + 插入),可以接受

查询时,将点 \(u\) 的父亲 + 重儿子插进平衡树,查出答案,最后再删掉即可

实现时还需要维护一个线段树 / 树状数组查每个点本身的点权

时间复杂度 \(O(n \log^2 n)\)

7.16

BZOJ P3648 寝室管理

AGC001C - Shorten Diameter

P7215 [JOISC 2020] 首都

7.17

P5642 人造情感(emotion) (树上路径最大独立集 DP)

先假设我们可以快速求出 \(W(S)\)

\(f(u, v)\),由于加入 \(\text{path}(u, v)\)\(W\) 变大,显然 \(\text{path}(u, v)\) 必然被选,其上的点均不能被占用

考虑\(\text{path}(u, v)\) 上的点及其所连的边全部删去以刻画"不能被占用";记删去路径后形成的若干树为 \(T_1, T_2, \cdots, T_k\),完全包含于 \(T_i\) 中的路径集为 \(S_i\),可得 \(w = W(S)-\sum_{i=1}^{k} W(S_i)\)

不妨令 \(1\) 为根;更进一步,易得删去路径后剩下的树只能是:

  • 原来以某个点为根的子树
  • 整棵树删去以某个点为根的子树后得到的树 (子树的补)

综上,考虑设计状态刻画"完全包含于某个子树 / 子树的补中的路径集的 \(W\) 值"

为求子树中的答案,我们令:

  • \(f_u\) 表示仅考虑 \(u\) 子树的答案
  • \(s_u\) 表示仅考虑 \(u\) 子树,且强制不占用 \(u\) 的答案

对初始值,考虑叶子 \(l\),有 \(f_l = \max_{u_i = l, v_i = l} w_i\)\(s_l = 0\);我们从下向上转移:

  • \(s_u \leftarrow \sum f_v\),其中 \(v\)\(u\) 的儿子

  • $ f_u \leftarrow s_u + \max { w_i-\sum_{k \in \text{path}(u_i, v_i)} (f_k-s_k) }$,其中 \(\text{lca}(u_i, v_i) = u\)

    解释:考虑先强制不选 \(u\),再拼上一条经过 \(u\) 的路径 (因此将每条路径挂在其两端点的 lca 上);这条路径上的点都不能被占用,因此对路径上的每个点 \(k\),减去 \((f_k-s_k)\) 表示\(k\) 点从可选可不选调整至必须不选的代价

    注意到,若 \(k\) 原本就不选,必有 \(f_k = s_k\);若 \(k\) 原本选,代价就是 \(f_k-s_k\),正确性没有问题

    那么 \(k\) 点的代价 \(f_k-s_k\) 是否会被重复计算?其实也不会,若路径经过 \(k \rightarrow v \rightarrow u\),若之前 \(v\) 点已经考虑了强制不选 \(k\) 的代价,在 \(u\) 点转移时将 \(f_v\) 改为 \(s_v\) 时会撤去这一代价,最终也只会在 \(k\) 处算一次

    考虑如何维护 \(\sum_{k \in \text{path}(u_i, v_i)} (f_k-s_k)\)

    其实就是单点加 + 链求和,树剖固然可做,不过树状数组维护根链可以少个 \(\log\)

    形式化的,设 \(i\) 的子树的 \(\text{dfn}\) 区间为 \([\text{dfn}_i, \text{bottom}_i]\)

    • \(i\) 单点加变为在 \(\text{dfn}_i\) 加,在 \(\text{bottom}_i+1\) 减 (转化为子树加,差分了一下)
    • \(i\) 查询相当于查 \([1, \text{dfn}_i]\)

容易发现,\(f_1 = W(S)\)

为求子树的补的答案,我们令 \(g_u\) 表示 \(u\) 子树的补的答案

在求出 \(g_u\) 后,我们给挂在 \(u\) 上的每条路径 \(\text{path}(u_i, v_i, w_i)\) 赋新权 \(w'_i = w_i+s_u-\sum_{k \in \text{path}(u_i, v_i)} (f_k-s_k)+g_u\),表示选择该条路径时,考虑子树内代价 + 子树外贡献的值 (即全局贡献的值)

对初始值,考虑根 \(1\),显然有 \(g_1 = 0\);我们从上向下转移,从 \(u\) 转移到儿子 \(v\) 时:

  • \(u\) 未被占用,有 \(g_v \leftarrow g_u+s_u-f_v\)

    解释:\(s_u-f_v\) 表示考虑 \(u\) 除儿子 \(v\) 的其他儿子的贡献

  • \(u\) 被形如 "\(u\) 的后代 \(\rightarrow u \rightarrow\) \(u\) 的祖先" 方向的路径占用,令这样的路径的权 (新权) 的 max 为 \(w'\),有 \(g_v \leftarrow w'-f_v\)

    由定义,这样的路径有且仅有一个端点是 \(u\) 的后代,且这个端点不是 \(v\) 的后代

    考虑如何维护这样的路径

    由于转移顺序是从上到下,转移到 \(g_v\) 时已经经过了 \(v\) 的所有祖先;因此考虑在每个点 \(p\) 处理挂在 \(p\) 上的路径对其后代的贡献

    设路径为 \(\text{path}(u_i, v_i, w'_i)\),将考虑 \(p\) 的儿子 \(q\) 的方向的转移;若 \(u_i\)\(v_i\)\(q\) 的后代 (不妨设此处 \(u_i\)\(q\) 的后代),则将 \(w'_i\) 插入 \(\text{dfn}_{u_i}\),对 \(q\) 的后代 \(s\) 及其儿子 \(t\),从 \(s\) 转移到 \(t\) 时查询"是 \(s\) 的后代且不是 \(t\) 的后代"的 \(\text{dfn}\) 区间的 max 即可

    形式化的,设 \(i\) 的子树的 \(\text{dfn}\) 区间为 \([\text{dfn}_i, \text{bottom}_i]\),查询 \([\text{dfn}_s, \text{dfn}_t-1] \bigcup [\text{bottom}_t+1, \text{bottom}_s]\) 中的 max 即可

    那么只需支持单点改 + 区间查 max 的线段树即可

    实现时千万注意顺序,先求出所有儿子 \(v\)\(g_v\),再将挂在 \(u\) 上的路径插入线段树,再递归求解 \(v\) 的子树

  • \(u\) 被形如 "\(u\) 的后代 \(\rightarrow u \rightarrow u\) 的后代" 方向的路径占用,同理令这样的路径的权的 max 为 \(w'\),有 \(g_v \leftarrow w'-f_v\)

    设路径为 \(\text{path}(u_i, v_i, w'_i)\),显然有 \(\text{lca}(u_i, v_i) = u\),换句话说,这些路径都是挂在 \(u\) 上的

    此时直接将这些路径排序,找到第一条满足 \(u_i\) 不是 \(v\) 的后代且 \(v_i\) 也不是 \(v\) 的后代的路径即可

    每条路径最多浪费两次访问 (\(u_i\)\(v\) 的后代 / \(v_i\)\(v\) 的后代),时间复杂度没问题

现在考虑如何求 \(f(u, v)\) (这里只看 \(W(S)\) 减去的东西)

对路径 \(\text{path}(u, v)\)非 lca 的每个点的每个儿子的子树 (不包含路径上的点) 被分离出来;同时,lca 子树的补也会被分离出来

简单容斥下,有:

  • 对不为 lca 的点 \(u\),贡献为 \(s_u-f_u\)
  • 对为 lca 的点 \(u\),贡献为 \(g_u+s_u\)

求这个应当是简单的

时间复杂度 \(O(n \log n)\)

7.18

CF566C - Logistical Questions (观察性质 + 点分治 - 移动重心)

7.19

P8250 交友问题 (图上根号分治)

CF2101E - Kia Bakes a Cake (点分治优化 DP)

CF1270F - Awesome Substrings (根号分治)

7.20

开摆 + 补 whk

7.21

P4168 [Violet] 蒲公英 (分块 - 维护块间答案)

P3203 [HNOI2010] 弹飞绵羊 (分块 - 维护跳出块信息)

P10590 磁力块 (分块 - 维护块内指针)

CF455D - Serega and Fun (分块 - 维护 deque)

7.22

P2500 [SDOI2012] 集合 (图上根号分治)

7.23

P1494 [国家集训队] 小 Z 的袜子 (莫队)

CF852I - Dating (树上莫队)

\(O(n \log n) - O(1)\) lca

7.24

CF940F - Machine Learning (带修莫队)

7.25

P5903 【模板】树上 K 级祖先 (长剖求 K 级祖先)

P3591 [POI 2015] ODW (长剖求 K 级祖先 + 根号分治)

CF1491H - Yuezheng Ling and Dynamic Tree (分块 - 弹飞绵羊 Trick + 均摊)

7.26

讲群论 + 调不出来题

7.27

P11527 [THUPC 2025 初赛] waht 先生的法阵 (分块 - 弹飞绵羊 Trick + 均摊)

P2481 [SDOI2010] 代码拍卖会 (数位 DP - 前后缀拆分 Trick + 循环节)

CF708C - Centroids (换根 DP)

P6419 [COCI 2014/2015 #1] Kamp (换根 DP)

7.28

P3647 [APIO2014] 连珠线 (观察性质 + 换根 DP)

不妨先令点 \(1\) 为根;容易发现,只存在 \(u - v - v'\) ( \(v \in \text{son}_u, v' \in \text{son}_v\) ) 与 \(v_1 - u - v_2\) ( \(v_1, v_2 \in \text{son}_u\) ) 两种连蓝链的结构

由题意,两条蓝链不能在非端点处相交;结构 \(1\)\(u\) 可作为端点,结构 \(2\)\(u\) 不能作为端点,这会给 DP 带来很大麻烦

考虑观察性质;红线只能连接新珠子与已有珠子,而对于结构 \(2\)\(u\) 一定是已有珠子;因此有:

  • 不存在两个结构 \(2\),使得 \(u_1, u_2\) 无祖先后代关系

那么我们必然可以找到一个点 \(rt\),使得以点 \(rt\) 为根时,所有结构 \(2\) 都变成结构 \(1\)

这启示我们进行换根 DP

先考虑子树内;令 \(f_{u, 0/1}\) 表示仅考虑 \(u\) 子树,\(u\) 所在蓝链长度为偶 / 奇的答案;转移为:

  • \(\displaystyle f_{u, 0} \leftarrow \sum_{v \in \text{son}_u} \max(f_{v, 0}, f_{v, 1}+w(u, v))\),表示每个儿子可以选择是否拼上点 \(u\)

  • \(\displaystyle f_{u, 1} \leftarrow f_{u, 0} + \max_{v \in \text{son}_u} (f_{v, 0} + w(u, v) - \max(f_{v, 0}, f_{v, 1}+w(u, v)))\),表示强行钦定一个儿子拼上点 \(u\)

    为辅助换根,此处套路地记录 \(\max\) 的最大值 \(s_{u, 1}\) 与次大值 \(s_{u, 0}\)

初始值为对叶子 \(u\)\(f_{u, 0} = 0\)\(f_{u, 1} = -\infty\)

再令 \(dp_{u, v, 0/1}\) 表示从 \(u\) 子树中挖去 \(v\) 子树 (\(v \in \text{son}_u\)),\(u\) 所在蓝链长度为偶 / 奇的代价:

  • \(\displaystyle dp_{u, v, 0} \leftarrow f_{u, 0}-\max(f_{v, 0}, f_{v, 1}+w(u, v))\)

  • \(\displaystyle dp_{u, v, 1} \leftarrow dp_{u, v, 0}+s_{u, 0}\) [\(f_{u, 1}\)\(\max\)\(v\) 处取得]

    \(\displaystyle dp_{u, v, 1} \leftarrow dp_{u, v, 0}+s_{u, 1}\) [\(f_{u, 1}\)\(\max\) 不在 \(v\) 处取得]

再考虑子树外;令 \(g_{u, 0/1}\) 表示挖去 \(u\) 的子树 (保留点 \(u\)),\(u\) 所在蓝链长度为偶 / 奇的答案;转移为:

  • \(\displaystyle g_{v, 0} \leftarrow \max(g_{u, 0}+dp_{u, v, 0}, \max(g_{u, 1}+dp_{u, v, 0}, g_{u, 0}+dp_{u, v, 1})+w(u, v))\)

    其中,\(g_{u, 0}+dp_{u, v, 0}\) 表示将点 \(v\) 单独空出来

    \(\max(g_{u, 1}+dp_{u, v, 0}, g_{u, 0}+dp_{u, v, 1})+w(u, v)\) 表示钦定 \(u\) 所在蓝链长为奇,再拼上点 \(v\) 断成两条链

  • \(\displaystyle g_{v, 1} \leftarrow g_{u, 0}+dp_{u, v, 0}+w(u, v)\),表示将点 \(v\) 拼到子树外长度为偶的蓝链上

初始值为 \(g_{1, 0} = 0, g_{1, 1} = -\infty\);最终答案即为 \(\max (f_{u, 0}+g_{u, 0}, f_{u, 1}+g_{u, 1})\)

时间复杂度 \(O(n)\)

P1453 城市环路 (基环树 DP)

P4381 [IOI 2008] Island (基环树 DP)

P2495 [SDOI2011] 消耗战 (虚树 DP)

7.29

P3233 [HNOI2014] 世界树 (虚树 DP)

CF1009F - Dominant Indices (长链剖分优化 DP)

P5904 [POI 2014] HOT-Hotels 加强版 (神仙树形 DP + 长链剖分优化 DP)

P2627 [USACO11OPEN] Mowing the Lawn G (单调队列优化 DP)

P2569 [SCOI2010] 股票交易 (单调队列优化 DP)

7.30

CF939F - Cutlet (设计状态 + 单调队列优化 DP)

P1912 [NOI2009] 诗人小G (决策单调性优化 DP - 二分队列)

CF868F - Yet Another Minimization Problem (决策单调性优化 DP - 分治 + 类莫队暴力)

P3120 [USACO15FEB] Cow Hopscotch G (类 CDQ 分治优化 DP)

P3810 【模板】三维偏序(陌上花开) (CDQ 分治)

7.31

CF449D - Jzzhu and Numbers (SOS DP + 容斥)

P6442 [COCI 2011/2012 #6] KOŠARE (SOS DP + 容斥)

P3287 [SCOI2014] 方伯伯的玉米田 (观察性质 + 二维树状数组优化 DP)

CF53E - Dead Ends (状压 DP + 钦定转移顺序)

CF1781F - Bracket Insertion (括号序列转 \(\pm\) 1 + 分析操作 + 合并同类项优化 DP)

8.1

AGC013E - Placing Squares (组合意义 - 平方变放两个球的方案数 + 矩阵快速幂优化 DP)

直接 DP 没有前途;考虑用组合意义刻画平方与连乘

\(n\) 个格子,你可以在其中插入若干隔板;有 \(m\) 个特殊格 \(x_1, x_2, \cdots, x_m\),你不能在 \(x_{i}, x_{i}+1\) 格间插入隔板

现在对于每个格子连续段,你需要选两个格子 (可重) 放入一个黑球一个白球,求总方案数

这样转化的好处是,每个连续段中只有 \(2\) 个球,按照这一性质设计状态更易于以后进行优化

\(f_{i, j}\) 表示当前在第 \(i\) 格,当前格到上个隔板间放了 \(j\) 个球的总方案数 ( \(j \in \{0, 1, 2\}\) )

\(i-1\) 不为特殊格,则有转移:

  • \(f_{i, 0} = f_{i-1, 0}+f_{i-1, 2}\) (不放隔板 / 放隔板)
  • \(f_{i, 1} = 2f_{i-1, 0}+f_{i-1, 1}+2f_{i-1, 2}\) (放黑或白球 / 不放球 / 放隔板+放黑或白球)
  • \(f_{i, 2} = f_{i-1, 0}+f_{i-1, 1}+2f_{i-1, 2}\) (放黑白球 / 放另一个球 / 不放隔板或放隔板+放黑白球)

同理,对特殊格,可得转移:

  • \(f_{i, 0} = f_{i-1, 0}\)
  • \(f_{i, 1} = 2f_{i-1, 0}+f_{i-1, 1}\)
  • \(f_{i, 2} = f_{i-1, 0}+f_{i-1, 1}+f_{i-1, 2}\)

初始值为 \(f_{0, 0} = 1\),答案即为 \(f_{n, 2}\)

对每个不包含特殊格的连续段矩阵快速幂优化即可;时间复杂度 \(O(m \log n)\)

CF1174E - Ehab and the Expected GCD Problem (观察性质 + DP)

CF1765C - Card Guessing (拆贡献 + 概率 DP 转计数 DP)

由于每次贡献为 \(1\),可先将猜对次数的期望转化为每次猜对的概率之和

由于每次猜花色是本质不同的决策,此处认为同种花色的牌也是本质不同的牌

设当前考虑第 \(i\) 张牌,令 \(K = \min(k, i-1)\),显然我们只关心前 \(K\) 张牌中,出现次数最少的花色还剩多少张牌

套路地将概率 DP 转化为计数 DP;不妨设 \(g_{i, j}\) 表示共 \(i\) 张牌,出现次数最少的花色出现 \(j\) 次的方案数 (显然有多种花色出现次数最少不影响)

直接转移似乎不好做,不过注意到花色只有 \(4\) 种,考虑用背包解决

\(f_{i, j, k}\) 表示考虑了前 \(i\) 种花色,总共选了 \(j\) 张牌,出现次数最少的花色出现 \(k\) 次的方案数

显然有转移 \(f_{i, j, k} \rightarrow f_{i+1, j+c, \min(k, c)} \cdot \dbinom{j+c}{c} \cdot \dbinom{n}{c} \cdot c!\) (分配插入位置,分配牌,分配顺序)

初始值为 \(f_{1, i, i} = \dbinom{n}{i} \cdot i!\);最终,我们有 \(g_{i, j} = f_{4, i, j}\)

\(h_i\) 表示选 \(i\) 张牌的方案数,显然有 \(h_i = \sum_{j=0}^{n} g_{i, j}\)

那么对于第 \(i\) 位,贡献为 \(\displaystyle \frac{\sum_{j=0}^{n} g_{K, j} \cdot (n-j)}{h_{K+1}}\);特别的,当 \(i=1\) 时,贡献为 \(\displaystyle \frac{1}{4}\)

注意,这里前 \(K\) 张牌再以前的牌的选择方案上下抵消了,故不考虑

那么最终答案即为 \(\displaystyle \frac{1}{4} + \sum_{i=2}^{4n} \frac{\sum_{j=0}^{n} g_{K, j} \cdot (n-j)}{h_{K+1}}\)

时间复杂度 \(O(n^3)\)

CF1726E - Almost Perfect (观察置换环性质 + 简单部分 DP 复杂部分枚举组合)

CF1842G - Tenzing and Random Operations (组合意义 - 连乘变乘法原理 + DP)

8.2

CF1750F - Majority (正难则反 + 前缀和优化类连续段 DP)

8.3

ABC262Ex - Max Limited Sequence (转化限制 + 线段树优化 DP)

首先,我们可以用数据结构求出每个位置的最紧上界 \(u_i\)

显然,无解当且仅当存在限制 \([l, r, x]\),使得 \(\max (u_l, u_{l+1}, \cdots, u_r) < x\)

注意到对每个位置,实际上我们只关心该位置是否取到上界

显然每个上界相互独立,考虑对每个上界分别计算方案数后乘起来 (对没有限制的位置,方案数为 \(m+1\) )

设当前上界为 \(c\);取出所有 \(u_i = c\) 的位置 \(i\) 排成一个序列,取出所有 \(X_j = c\) 的限制 \(j\)

注意到对于每个限制 \(j\),其本质上是要求序列中一段下标区间内有至少 \(1\) 个位置取到上界

这启发我们记录序列中取到上界的位置;令 \(f_{i, j}\) 表示当前在第 \(i\) 位,上一个取到上界的位置为 \(j\) 的方案数

先不考虑限制,显然有转移:

  • \(f_{i, i} \leftarrow f_{i-1, j}\),表示位置 \(i\) 取到上界
  • \(f_{i, j} \leftarrow f_{i-1, j} \times c\),其中 \(i \ne j\),表示位置 \(i\) 未取到上界

对于每个限制,我们将其挂在右端点考虑;具体的,对于限制 \([l, r]\),在 \(i=r\) 时清空所有 \(j < l\)\(f_{i, j}\)

初始值为 \(f_{0, 0} = 1\),答案为 \(\sum_{j} f_{\text{len}, j}\)

这显然可以通过支持单点改 + 区间乘 + 区间推平 + 全局和的线段树维护

时间复杂度 \(O(n \log n)\)

AGC030F - Permutation and Minimum (转化限制 + DP)

先转化下题意

\(1, 2, \cdots, 2n\) 排成一排,从左向右连线匹配,匹配值为左侧数的值,求方案数

\(v_u = 0/1\) 表示 \(u\)\(a_i\) 中不存在 / 存在,对匹配 \((x, y)\) ( \(x < y\) ),分类讨论:

  • \(v_x = 1, v_y = 1\),此时匹配位置和值均确定,直接扔掉即可
  • \(v_x = 1\)\(v_y = 1\),此时匹配位置确定
  • \(v_x = 0, v_y = 0\),此时可以自由分配匹配位置

注意到不好用 DP 刻画 "自由分配匹配位置",不过你发现第三类匹配的个数确定,考虑先转化为无序,最后乘阶乘定序

因此,两种匹配方案不同,当且仅当:

  • 匹配值不同,即存在位置 \(i\) 在第一种方案中是左端点,第二种方案中不是
  • 匹配位置不同,即存在匹配 \((i, x), (i, y)\) 使得 \(x \ne y\)\(v_x = 1, v_y = 1\)

考虑从大向小 DP,逐个确定匹配位置,记 \(f_{i, j, k}\) 表示从 \(2n\) 填到 \(i\),有 \(j\)\(v_x = 0\) 的右端点,有 \(k\)\(v_x = 1\) 的右端点

易得转移:

  • \(v_i = 0\) 时:
    • \(f_{i, j, k} \leftarrow f_{i+1, j+1, k}\),表示匹配一个 \(v_x = 0\) 的右端点
    • \(f_{i, j, k} \leftarrow f_{i+1, j, k+1} \times (k+1)\),表示匹配一个 \(v_x = 1\) 的右端点,需要考虑匹配位置
    • \(f_{i, j, k} \leftarrow f_{i+1, j-1, k}\),表示不匹配
  • \(v_i = 1\) 时:
    • \(f_{i, j, k} \leftarrow f_{i+1, j+1, k} \times (j+1)\),表示匹配一个 \(v_x = 0\) 的右端点
    • \(f_{i, j, k} \leftarrow f_{i+1, j, k-1}\),表示不匹配

初始值为 \(f_{2n+1, 0, 0} = 1\),答案为 \(f_{1, 0, 0}\)

时间复杂度 \(O(n^3)\)

8.4

ARC106E - Medals (Hall 定理 + SOS DP)

CF21D - Traveling Graph (欧拉回路状压 DP)

8.5

CF1773G - Game of Questions (观察性质 - 去除无用状态 + 状压 DP)

注意到 \(m \le 17\),考虑对人状压一下

不妨令 \(f_S\) 表示场上剩余的人组成的集合为 \(S\) 时,Genie 的获胜概率

若转移时直接枚举问题,有可能会选重,记在状态里又接受不了;但注意到,重复选择问题不会使 \(S\) 变化,因此无需考虑这件事

具体的,设有 \(c_0\) 种问题可以使 \(S\) 减少,\(c_1\) 种问题可以使 \(S\) 变成 \(T\) ( $ T \varsubsetneqq S$ ),即有 \(\displaystyle f_S \leftarrow f_T \times \frac{c_1}{c_0}\) (只在 \(S\) 产生变化时统计)

直接 \(O(n2^m)\) 枚举问题显然无法接受,考虑预处理 \(g_{S, T}\) ( \(T \subset S\) ) 表示使 \(S\) 变成 \(T\) 的问题数量

\(g_{S, T}\) 的转移,考虑钦定一个 \(x (x \notin S)\),则所有使 \(S\) 变成 \(T\) 的问题可分为同时 ban 掉 \(x\) 与不同时 ban 掉 \(x\) 两类

显然有转移 \(g_{S, T} \leftarrow g_{S \cup \{x\}, T} + g_{S \cup \{x\}, T \cup \{x\}}\)

\(f_S\),则有转移 \(\displaystyle f_S \leftarrow \frac{\sum_{T \varsubsetneqq S} f_{T} g_{S, T}}{n-g_{S, \varnothing}-g_{S, S}}\)

初始值为对所有 \(g_{S, \varnothing}+g_{S, S} = n\)\(S\)\(f_{S}= [1 \in S]\);答案即为 \(f_{\{1, 2, \cdots, m\}}\)

时间复杂度为 \(O(nm + 3^m)\)

P9129 - [USACO23FEB] Piling Papers G (区间 DP 套类数位 DP)

8.6 - 8.9

准备讲课 PPT + 补 whk

8.10 - 8.16

军训

8.17

ARC103F - Distance Sums (观察性质 + 类拓扑思想)

CF1528C - Trees of Tranquillity (虚树思想贪心)

CF842E - Nikita and game (树的直径性质 - 交于一点或一边 + 维护左右集合)

CF2108E - Spruce Dispute (拆贡献 + 贪心 - 最大子树最小取重心)

CF1783G - Weighed Tree Radius (补齐对称性 + 观察性质 + 线段树维护区间直径)

AGC018D - Tree and Hamilton Path (拆贡献 + 贪心 - 最大子树最小取重心 + 回路减边变路径)

8.18

8.18 T1 - Rainbow 的信号 (拆位 + 拆贡献)

8.18 T2 - Freda 的传呼机 (仙人掌最短路)

8.18 T4 - Tree (分数规划 + 树形 DP)

8.19

8.18 T3 - Circle (观察性质 + 类数位 DP)

P12205 [COI 2022] 通行证件 / Vinjete (线段树维护区间 > 0 个数)

8.20

P6348 [PA 2011] Journeys (线段树优化建图)

ABC414G - AtCoder Express 4 (线段树优化建图 - 左右端点差分)

P6453 [COCI 2008/2009 #4] PERIODNI (笛卡尔树上 DP)

P3809 【模板】后缀排序 ( \(O(n \log n)\) SA)

\(\text{sa}_i\) 表示排名为 \(i\) 的后缀位置,\(\text{rk}_i\) 为后缀 \(\text{suf}_i\) 的排名

做法 1:\(O(n \log^2 n)\)

考虑直接对每个后缀排序,这样是 \(O(n^2 \log n)\)

考虑优化比较;二分哈希求 \(\text{lcp}\) 后比较下一位即可,这样单次比较 \(O(\log n)\),总时间复杂度 \(O(n \log^2 n)\)

做法 2:\(O(n \log^2 n)\)

考虑倍增的思想求解

\(\text{rk}_{i}^{j}\) 表示考虑所有长为 \(2^j\) 的子串 (不足补极小值),从 \(i\) 开始的排名,\(\text{sa}_{i}^{j}\) 类似

初始时,我们对每个字符排序可得 \(\text{rk}_{i}^{1}\)\(\text{sa}_{i}^{1}\)

\(j\) 倍增到 \(j+1\) 时,对所有位置 \(i\)\(\text{rk}_{i}^{j}\) 以第 \(1\) 关键字、\(\text{rk}_{i+2^j}^{j}\) 以第 \(2\) 关键字排序即可

注意,需要特别处理 \(\text{rk}_{p}^{j} = \text{rk}_{q}^{j}\)\(\text{rk}_{p+2^j}^{j} = \text{rk}_{q+2^j}^{j}\) 的情况,此时 \(\text{rk}_{p}^{j+1} = \text{rk}_{q}^{j+1}\);排好序后重新扫一遍即可

只需做到 \(2^j \ge n\),共 \(O(\log n)\) 轮,总时间复杂度 \(O(n \log^2 n)\),瓶颈在排序

做法 3:\(O(n \log n)\)

做法 2 的瓶颈在排序,用基数排序 (做两次计数排序) 优化即可

实现上的小细节:

  • \(1\) 次排序无需考虑第 \(2\) 关键字

  • 对第 \(2\) 关键字排序无需计数排序:

    for (int i=n-w+1; i<=n; i++) tot++, id[tot] = i (处理 \(i+w > n\) 的情况,此时没有先后顺序)

    for (int i=1; i<=n; i++) if (sa[i] > w) tot++, id[tot] = sa[i]-w (直接处理 \(i+w\) 的顺序)

  • 排好序后需要重新扫一遍处理 \(\text{rk}\) 相同的情况

  • 可动态令基数排序的值域 \(V = \max\{\text{rk}_i\}\)

  • \(\max\{\text{rk}_i\} \ge n\) 时无需继续排序,直接 break 即可

\(\text{h}_i = \text{lcp}(\text{suf}_{\text{sa}_{i-1}}, \text{suf}_{\text{sa}_{i}})\),考虑如何求 \(\text{h}_i\)

结论 1:\(\text{h}_{\text{rk}_i} \ge \text{h}_{\text{rk}_{i-1}}-1\)

\(\text{h}_{\text{rk}_{i-1}} \le 1\) 时,显然成立

\(\text{h}_{\text{rk}_{i-1}} > 1\) 时,令旧 \(\text{lcp}\)\(\text{aA}\),其中 \(\text{a}\) 为字符,\(\text{A}\) 为串;因此,令 \(\text{suf}_{i-1}\)\(\text{aAD}\),另一个为 \(\text{aAB}\)

因此,我们有 \(\text{suf}_i\)\(\text{AD}\),且存在 \(\text{AB}\);由于 \(\text{rk}_i-1\)\(\text{rk}_i\) 仅小 \(1\),因此有 \(AB \le \text{suf}_{\text{sa}_{\text{rk}_i-1}} < AD\)

综上,新 \(\text{lcp}\) 至少为 \(\text{A}\),证毕

我们可以根据这一性质暴力求 \(\text{h}_i\) (初始值 \(\text{h}_1 = 0\) )

结论 2:\(\displaystyle \text{lcp}(\text{suf}_i, \text{suf}_j) = \min_{\text{rk}_i+1 \le k \le \text{rk}_j} \text{h}_k\)

显然,必有 \(\displaystyle \text{lcp}(\text{suf}_i, \text{suf}_j) \ge \min_{\text{rk}_i+1 \le k \le \text{rk}_j} \text{h}_k\)

感性理解上,由于我们按字典序枚举,\(\text{lcp}\) 只要掉下去就回不来了,成立

8.21

AT_ddcc2020_final_c - Smaller-Suffix-Free Sequences (SA)

题意:给定串 \(s\),对其每个后缀,求出该后缀的一个最长前缀,满足这个前缀为 Lyndon 串

一个串称为 Lyndon 串,当且仅当其字典序严格小于其所有后缀;\(1 \le |s| \le 2 \times 10^5\)

令原串为 \(s\)\(s\) 的一个后缀的前缀为 \(t\)\(t\) 的一个后缀为 \(t'\)

容易发现,\(t < t'\)\(t+x < t'+x\) 是等价的;那么我们只需判断原串后缀与后缀的字典序关系即可

这启示我们建出 SA;则原题可转化为:

  • 对每个 \(1 \le i \le n\),求出最大的 \(j\) 使得 \(\displaystyle \text{rk}_i = \min_{i \le p \le j} \text{rk}_p\)

单调栈维护即可;时间复杂度 \(O(n \log n)\),瓶颈在建 SA

P2178 [NOI2015] 品酒大会 (SA - 并查集维护 \(h_i\) )

由于有经典结论 \(\displaystyle \text{lcp}(\text{suf}_i, \text{suf}_j) = \min_{\text{rk}_i+1 \le k \le \text{rk}_j} \text{h}_k\),考虑建出 SA

考虑从大到小加入 \(\text{h}_{\text{rk}_i}\),每个 \(\text{h}_{\text{rk}_i}\) 放在 \(\text{rk}_i\) 位置上,过程中会形成许多连续段;考虑用并查集维护

具体的,对于连续段 \([l, r]\),其对应满足 \(l-1 \le \text{rk}_i \le r-1\)\(l \le \text{rk}_j \le r\) ( \(i < j\) ) 的 \(\text{lcp}(\text{suf}_i, \text{suf}_j)\)

对第一问,连续段 \([l, r]\) 对应的选择方案数为:

  • \(l = 1\),则为 \(\displaystyle 1+2+\cdots+(r-1) = \frac{1}{2} r(r-1)\)
  • \(l \ne 1\),则为 \(\displaystyle 1+2+\cdots+(r-l+1) = \frac{1}{2} (r-l+2)(r-l+1)\)

这启示我们维护连续段的左右端点,合并时减去两个小区间贡献再加上新区间贡献即可

对第二问,合并 \([l_1, r_1], [l_2, r_2]\) 时 (不妨设 \(l_2 > r_1\) ):

  • 左端点取在 \([\max(1, l_1-1), r_1-1]\),右端点取在 \([l_1, r_1]\),已经在计算 \([l_1, r_1]\) 的答案时贡献过

  • 左端点取在 \([\max(1, l_2-1), r_2-1]\),右端点取在 \([l_2, r_2]\),已经在计算 \([l_2, r_2]\) 的答案时贡献过

  • 左端点取在 \([\max(1, l_1-1), r_1-1]\),右端点取在 \([l_2, r_2]\)

    这启示我们对区间 \([l, r]\) 维护 \(a\)\([\text{sa}_l, \text{sa}_{r-1}]\) 的最大 / 次大 / 最小 / 次小值

    合并时,我们:

    • 用 ( \([l_1, r_1]\) 的相关值 + \(a_{\text{sa}_{l_1-1}} [l_1 \ne 1]\) ) 与 ( \([l_2, r_2]\) 的相关值 + \(a_{\text{sa}_{r_2}}\) ) 更新 \([l_1, r_2]\) 答案
    • 用 ( \([l_1, r_1]\) 的相关值 + \(a_{\text{sa}_{r_1}}\) ) 与 ( \([l_2, r_2]\) 的相关值 ) 更新 \([l_1, r_2]\) 相关值
    • 根据实现不同,当 \(l_1 = r_1\) 时可能需要特殊处理 (如补上 \(a_{\text{sa}_{l_1}}\) )

时间复杂度 \(O(n \log n)\),瓶颈在建 SA

8.22

P9664 [ICPC 2021 Macao R] LCS Spanning Tree (SA - 只需考虑 sa 相邻的 lcs)

首先考虑只有两个串 \(s_i, s_j\) 怎么做

\(\text{lcs}\) 自然启发我们建 SA,这启示我们将 \(s_i, s_j\) 拼接起来,在 \(s_i\) 中选取左端点 \(l\),在 \(s_j\) 中选取右端点 \(r\)\(\text{lcp}\)

此时出现了两个问题:

  1. \(\text{lcp}(\text{suf}_l, \text{suf}_r) \ge |s_i|-l+1\),即 \(\text{lcp}\) 超出 \(s_i\)

    这可以通过在 \(s_i, s_j\) 间添加特殊连接符规避

  2. 暴力选取 \(l, r\) 在时间复杂度上无法接受

    注意到只有排名相邻的后缀是有用的,枚举排名 \(i\),贡献为 \(\text{lcp}(\text{suf}_{\text{sa}_{i-1}}, \text{suf}_{\text{sa}_i}) = \text{h}_i\)

    综上,判掉 \(\text{sa}_{i-1}\)\(sa_i\) 在一个串中的情况,连边 \((\text{sa}_{i-1}, \text{sa}_i, \text{h}_i)\) 即可

多个串没有本质区别,全部拼起来,中间加上不同的连接符即可

时间复杂度 \(O(n \log n)\)

CF547E - Mike and Friends (SA + 二维数点)

省流:我觉得我真想不清楚细节,所以写的会繁琐亿点

类比上题,套路地将 \(s_1, s_2, \cdots, s_n\) 拼成新串,中间加上不同的分割符;记新串中 \(s_i\) 的对应位置为 \([\text{st}_i, \text{ed}_i]\)

对于查询 \((l, r, k)\),对满足条件的新串位置 \(i\),考虑分讨限制条件:

  • 显然要求 \(i \in [\text{st}_l, \text{ed}_r]\)
  • \(p = \text{st}_k\),若 \(\text{rk}_i < \text{rk}_{p}\),则有 \(\displaystyle \text{lcp}(\text{suf}_i, \text{suf}_p) = \min_{\text{rk}_i+1 \le q \le \text{rk}_p} \text{h}_q = |s_k|\)
  • \(\text{rk}_i = \text{rk}_{p}\),事实上即 \(i = p\),显然成立
  • \(\text{rk}_i > \text{rk}_{p}\),则有 \(\displaystyle \text{lcp}(\text{suf}_i, \text{suf}_p) = \min_{\text{rk}_p+1 \le q \le \text{rk}_i} \text{h}_q = |s_k|\)

这启示我们对每个位置 \(i\) 维护:

  • 最靠前的 \(l_i\),满足 \(\displaystyle \min_{l \le j \le \text{rk}_i} \text{h}_{j} = \text{h}_{\text{rk}_i}\)
  • 最靠后的 \(r_i\),满足 \(\displaystyle \min_{\text{rk}_{i+1} \le j \le r} \text{h}_{j} = \text{h}_{\text{rk}_{i+1}}\)

这里直接二分维护即可

回到询问 \((l, r, k)\),对满足条件的新串位置 \(i\),考虑转化限制条件:

  • \(i \in [\text{st}_l, \text{ed}_r]\)
  • \(\text{rk}_i\) 也需在一个区间 \([l', r']\) 内,令 \(p = \text{st}_k\),具体的:
    • \(\text{h}_{\text{rk}_p} = |s_k|\),则左半区间成立,有 \(l' = l_k\);反之 \(l' = \text{rk}_p\)
    • \(\text{h}_{\text{rk}_{p+1}} = |s_k|\),则右半区间成立,有 \(r' = r_k\);反之 \(r' = \text{rk}_p\)

那么直接二维数点即可;时间复杂度 \(O(n \log n)\)

8.23

CF1923F - Shrink-Reverse (观察性质 + SA)

首先考虑没有翻转操作怎么做

我们每次必然贪心地将最靠前的 \(1\) 与最靠后的 \(0\) 交换;双指针维护即可,这部分时间复杂度 \(O(n)\)

考虑观察翻转操作的性质

显然,\(1\) 次翻转可以去前导零,\(2\) 次可以去后导零,\(\ge 3\) 次是没有意义的

对于 \(2\) 次翻转,我们发现去后导零并没有改变答案;若翻转后再交换,显然可以不劣地等效为先交换再翻转

综上,只需考虑 \(1\) 次翻转的情况,且这次翻转必然最后进行

类比没有翻转的情况,一个 naive 的想法是将最靠后的 \(1\) 与前导零的末尾交换

\(00101100\) 的情况就可以 hack 掉这个做法,因为我们可以与中间的 \(0\) 交换以缩小长度

这启示我们先确定最小长度 \(L\);显然先翻转 \(s\) 不影响答案,以下的 \(s\) 均指翻转后的串

对每个 \(i\),考虑求出最靠前的 \(r_i\) 使得可以将所有 \(1\) 换到 \([i, r_i]\) 中:

  • \([i, r_i]\)\(0\) 的个数为 \(c_0\)\([i, r_i]\)\(1\) 的个数为 \(c_1\)

    \([i, r_i]\) 合法等价于 \(c_1 \le k-1\) (能换进来) 且 \(c_1 \le c_0\) (有地方容纳)

\(i\) 增大时,\(c_0\) 不增,\(c_1\) 不降,\(r_i\) 也是单调的;于是这部分也可以双指针做到 \(O(n)\)

接下来考虑最小化字典序;显然换进来的 \(1\) 会优先向后放,比的实际上是后缀的一段前缀的字典序

这启示我们跑 SA,按 \(\text{rk}\) 从小到大枚举,第一个合法的长度为 \(L\) 的前缀就是答案;证明:

  • \(\text{lcp} > L\),由于外面的 \(1\) 全部被换进来,已经完全相同,前后顺序没有影响

  • \(\text{lcp} \le L\) 且换进来的 \(1\) 没有影响 \(\text{lcp}\),直接按 \(\text{rk}\) 排就是对的

    \(\text{lcp} \le L\) 且换进来的 \(1\) 影响了 \(\text{lcp}\),由于里面 \(1\) 的总数确定,一定是将一段后缀部填成 \(1\),前后顺序没有影响

时间复杂度 \(O(n \log n)\),瓶颈在建 SA

8.24

P4094 [HEOI2016/TJOI2016] 字符串 (SA + 二分答案 + 主席树 - 区间查非严格前驱 / 后缀)

子串 \(\text{lcp}\) 自然启示我们建 SA,同时把子串拼成后缀考虑

对于查询 \((a, b, c, d)\),其答案为:

  • \(\displaystyle \max_{a \le p \le b} \{\min\{\text{lcp}(\text{suf}_p, \text{suf}_c),\ b-p+1,\ d-c+1\}\}\)

    这个式子表示对后缀求 \(\text{lcp}\) 后限制不能超出子串长度

限制不能超出 \([a, b]\) 子串长度的 \(b-p+1\) 一项很烦,考虑怎么去掉

考虑二分答案 \(\text{mid}\) 再刻画限制,提前确定合法区间 \([a, b-\text{mid}+1]\),这样就无需考虑这个问题

套路地,对于 \(a \le i \le b-\text{mid}+1\),我们对 \(\text{lcp}(\text{suf}_i, \text{suf}_c)\) 分类讨论:

  • \(\text{rk}_i \le \text{rk}_c-1\),此时 \(\displaystyle \text{lcp}(\text{suf}_i, \text{suf}_c) = \min_{\text{rk}_i+1 \le p \le \text{rk}_c} \text{h}_p\),只需取 \(\le \text{rk}_c-1\) 的最大的 \(\text{rk}_i\) 计算
  • \(\text{rk}_c+1 \le \text{rk}_i\),此时 \(\displaystyle \text{lcp}(\text{suf}_i, \text{suf}_c) = \min_{\text{rk}_c+1 \le p \le \text{rk}_i} \text{h}_p\),只需取 \(\ge \text{rk}_c+1\) 的最小的 \(\text{rk}_i\) 计算
  • \(\text{rk}_i = \text{rk}_c\),此时 \(i = c\),答案即为 \(\min\{b-i+1, d-i+1\}\)

综上,我们需要支持区间查非严格前驱 / 后继

一个直观的想法是二分排名 + 静态区间第 \(k\) 小,上主席树,总时间复杂度 \(O(n \log^3 n)\)

事实上,可以发现二分排名是不必要的,设查询区间为 \([l, r]\)

  • 若对 \(x\) 求前驱,线段树上二分查出 \(x\) 的排名,再对排名求值即可
  • 若对 \(x\) 求后继,线段树上二分查出 \(x-1\) 的排名,再对排名 \(+1\) 求值即可

综上,我们维护 SA + 主席树 + 对 \(\text{h}_i\) 的 ST 表,总时间复杂度 \(O(n \log^2 n)\)

8.25

P4248 [AHOI2013] 差异

将式子拆成两部分,即 \(\displaystyle \sum_{1 \le i < j \le n} (|\text{suf}_i|+|\text{suf}_j|)\)\(\displaystyle \sum_{1 \le i < j \le n} \text{lcp}(\text{suf}_i, \text{suf}_j)\)

前半部分易知为 \(\displaystyle \sum_{i=1}^{n-1} (\frac{i(i+1)}{2}+(n-i+1)(n-i))\),考虑如何求后半部分

\(i = j\) 的情况本身不合法无需统计,易得 \(\text{h}_i\) 上的每个区间 \([l, r]\) 都会贡献 \(\displaystyle \min_{l \le p \le r} \text{h}_p\)

对每个 \(i\),处理出:

  • 最靠前的 \(\text{ls}_i\) 使得 \(\displaystyle \min_{\text{ls}_i \le p \le i}\text{h}_p = \text{h}_i\) 且在 \(\text{h}_i\) 处唯一取到
  • 最靠后的 \(\text{rs}_i\) 使得 \(\displaystyle \min_{i \le p \le \text{rs}_i} \text{h}_p = \text{h}_i\)

\([\text{ls}_i, i]\) 中选左端点,\([i, \text{rs}_i]\) 中选右端点,贡献即为 \((i-\text{ls}_i+1) \times (\text{rs}_i-i+1) \times \text{h}_i\)

可二分 + ST 表或单调栈维护 \(\text{ls}_i\)\(\text{rs}_i\),时间复杂度 \(O(n \log n)\)

8.26

P5161 WD与数列

对位差相等是困难的;注意到两序列增量相同,考虑对原序列差分

问题转化为:计数存在多少对 \([l_1, r_1], [l_2, r_2]\),使得 \(r_1 < l_2\)\(a_{[l_1+1, r_1]} = a_{[l_2+1, r_2]}\) (注意第 \(1\) 位可以不同)

那么贡献分为两部分:

  • 只有第 \(1\) 位,贡献为 \(\binom{n}{2}\)

  • 扔掉第 \(1\) 位,计数存在多少对不交且不相邻的相等子串

    注意,虽然此处视为 "扔掉",最后还是要往前拼 \(1\) 位的,子串左端点不能为 \(1\)

考虑处理不交且不相邻的相等子串对数

令靠前的子串开头为 \(i\),靠后的为 \(j\),考虑将 "不相邻" 刻画为对 \(j-i-1\)\(\min\)

答案式子为 \(\displaystyle \sum_{1 < i < j \le n} \min\{\text{lcp}(\text{suf}_i, \text{suf}_j), j-i-1\}\)

考虑先求出 \(\displaystyle \sum_{1 < i < j \le n} \text{lcp}(\text{suf}_i, \text{suf}_j)\),再把 \(\ge j-i\) 的部分换成 \(j-i-1\)

前半部分是容易的,可以参考上道题

对于后半部分,考虑枚举 \(\text{len} = j-i\),使用 P1117 [NOI2016] 优秀的拆分 的 trick:

  • \(\text{len}, 2 \times \text{len}, 3 \times \text{len}, \cdots\) 处设关键点

  • 对关键点 \(k\)\(k+\text{len}\),求出 \(i \in [\max\{2, k-len+1\}, k]\) 的贡献

    注意到这样处理不到 \(i\) 在倒数第二个关键点后的情况,不过此时必有 \(\text{lcp} < \text{len}\),没有贡献

  • 求出 \(\text{lcp}(\text{suf}_k, \text{suf}_{k+\text{len}})\)\(\text{lcs}(\text{pre}_k, \text{pre}_{k+\text{len}})\),则只需考虑 \(i \in [\max\{2, k-\min\{\text{len}, \text{lcs}\}+1\}, k]\)

    此时 \(\text{lcp}\) 长度的贡献为等差数列,可以 \(O(1)\) 求出

使用 SA 维护原串与反串的后缀 \(\text{lcp}\) 即可

时间复杂度 \(O(n \log n)\)

8.27

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

SAM (后缀自动机),可以始终在 \(O(|s|)\) 的结点和边的代价下存储 \(s\) 的子串信息,将 \(s\) 的子串高度压缩以存储

下面给出一些定义:

  • \(\text{endpos}\):对 \(s\) 及其子串 \(t\),定义 \(t\)\(\text{endpos}\) 集合为 \(s\) 中所有 \(t\) 出现的结束位置构成的集合

    例:对 aabab,子串 ab\(\text{endpos}\) 集合为 \(\{3, 5\}\)

    引理 1:对 \(s\) 及其子串 \(u, v (|v| \le |u|)\)\(u\)\(v\)\(\text{endpos}\) 集合相同 \(\iff v\)\(s\) 中每次出现都是以 \(u\) 的后缀的形式

  • \(\text{endpos}\) 等价类:\(\text{endpos}\) 相同的所有子串构成的集合

    例:对 aabab,子串 abb 同属一个 \(\text{endpos}\) 等价类

    引理 2\(\text{endpos}\) 等价类中子串的长度连续,且所有子串均为最长子串的后缀

SAM 中的每个节点实际上代表一个 \(\text{endpos}\) 等价类

从初始节点 \(\text{rt}\) 到节点 \(u\) 会经过许多转移边,将转移边上的字符写下来形成字符串,这些字符串的 \(\text{endpos}\) 集合都相同

在 SAM 上的每个节点 \(u\),我们维护:

  • \(\text{len}\):当前 \(\text{endpos}\) 等价类中最长子串的长度

  • \(\delta(u, c)\)\(u\) 经过转移边 \(c\) 到达的节点

  • \(\text{link}\) (后缀链接):设当前 \(\text{endpos}\) 等价类中最长子串为 \(p\),最长的不属于当前 \(\text{endpos}\) 集合的 \(p\) 的后缀为 \(q\)

    \(u\) 的后缀链接 \(\text{link}(u)\) 指向代表 \(q\) 所在 \(\text{endpos}\) 等价类的节点

    引理 3:将所有 \(u\)\(\text{link}(u)\) 连边,会形成一个树形结构

    证明:显然只会从长串向短串连边,最终都连到初始节点 \(\text{rt}\),必然形成以 \(\text{rt}\) 为根的树

    我们也将这一树形结构称为 \(\text{parent tree}\)

初始时,创建初始节点 \(\text{rt}\),代表空串;令 \(\text{len}(\text{rt}) = 0\)\(\text{link}(\text{rt}) = -1\)

考虑增量构造 SAM,设原串为 \(s\),每次加入一个字符 \(c\) 变为 \(s+c\),创建新节点 \(u\) 代表当前插入状态

\(s+c\) 的末尾位置为 \(i\),则 \(u\) 实际代表的 \(\text{endpos}\) 集合为 \(\{i\}\)

设上次插入状态的对应节点为 \(v\),考虑维护 \(u\)\(\text{len, link}\) 及其他节点向 \(u\) 的转移关系:

  • 显然有 \(\text{len}(u) = \text{len}(v)+1\)

  • 考虑尝试在 \(s\) 的每个后缀 \(\text{endpos}\) 等价类的末尾追加 \(c\) 形成 \(s+c\) 的后缀 \(\text{endpos}\) 等价类

    我们从 \(v\) 开始跳 \(\text{link}\),设当前跳到的节点为 \(p\),对应 \(\text{endpos}\) 等价类中的最长子串为 \(t\)

    • \(\delta(p, c)\) 不存在,说明子串 \(t+c\)\(s\) 中不存在,在 \(s+c\) 中的 \(\text{endpos}\) 集合就是 \(\{i\}\)

      易知 \(t+c\)\(s+c\) 同属一个 \(\text{endpos}\) 等价类,因此,令 \(\delta(p, c) = u\)

    考虑一直跳 \(\text{link}\) 直到跳到 \(-1\) 或出现第一个满足 \(\delta(p, c)\) 存在的节点 \(p\)

    • 若跳到 \(-1\),说明 \(c\) 这个字符在 \(s\) 中不存在,直接令 \(\text{link}(u) = \text{rt}\) 即可

    • 若出现第一个满足 \(\delta(p, c)\) 存在的节点 \(p\),令 \(q = \delta(p, c)\)

      • \(\text{len}(q) = \text{len}(p)+1\),则 \(t+c\) 刚好为最长的 \(\text{endpos}\) 等价类不为 \(\{i\}\) 的后缀,令 \(\text{link}(u) = q\) 即可

      • 需要注意,此时 \(q\) 代表的 \(\text{endpos}\) 等价类中的最长子串不一定为 \(p+c\),可能更长

        例:对字符串 abb,插入最后一个 b 前 SAM 结构如下:

        • 节点 \(0\)\(\text{endpos}\) 等价类中为空串,\(\text{link} = -1\)
        • 节点 \(1\)\(\text{endpos}\) 等价类中为 {a}\(\text{link} = 0\),连边 \(\delta(0, a) = 1\)
        • 节点 \(2\)\(\text{endpos}\) 等价类中为 {ab, b}\(\text{link} = 0\),连边 \(\delta(0, b) = 2, \delta(1, b) = 2\)

        插入最后一个 b 时,我们会跳 \(\text{link}\)\(0\),此时 \(p = 0, q = \delta(0, b) = 2\)

        此时节点 \(2\) 代表的 \(\text{endpos}\) 等价类中除了 b,还有更长的 ab

        以此例为例,我们发现节点 \(3\) (即新创建的 \(u\) ) 代表的 \(\text{endpos}\) 等价类应为 {abb, bb}

        此时节点 \(3\)\(\text{link}\) 对应的 \(\text{endpos}\) 等价类应为 b;这启示我们将节点 \(2\) 进行 "分裂",变为 abb

      • 综上,若 \(\text{len}(q) > \text{len}(p)+1\),考虑将节点 \(q\) 分裂出一个 \(q'\),后缀长度分界线即为 \(\text{len}(p)+1\)

        \(q\) 代表的 \(\text{endpos}\) 集合为 \(S\),可视为新节点 \(q\) 仍维护 \(\text{endpos}\) 集合 \(S\),新节点 \(q'\) 维护 \(S \cup \{i\}\)

        具体的,先克隆 \(q' = q\) (即储存信息全部相同),令:

        • \(\text{len}(q') = \text{len}(p)+1\)
        • \(\text{link}(u) = q'\)
        • \(\text{link}(q) = q'\)

        接下来从节点 \(p\) 继续跳 \(\text{link}\),将所有 \(\delta(p', c) = q\) 改为 \(\delta(p', c) = q'\) 即可

现在我们已经能够建出 SAM,回到本题

考虑暴力枚举每个节点 \(i\),将 \(\text{link}(i)\)\(i\) 连边,建出 \(\text{parent tree}\)

记录每次插入时的节点 \(u\),将这些点赋权 \(1\),其他点赋权 \(0\) (实现时最好不要直接在 SAM 节点上记录权,复制时容易出错)

易知对于节点 \(i\),其代表的 \(\text{endpos}\) 集合的大小即为 \(i\) 子树内 \(1\) 的个数

对于一个 \(\text{endpos}\) 等价类,我们肯定取最长的子串,长度即为 \(\text{len}(i)\);那么 dfs 一遍取 \(\max\) 即可

若直接开数组存 \(\delta(u, c)\),时间复杂度 \(O(n)\),空间复杂度 \(O(n|\Sigma|)\)

若使用 \(\text{map}\)\(\delta(u, c)\),时间复杂度 \(O(n \log |\Sigma|)\),空间复杂度 \(O(n)\)

SP1812 LCS2 - Longest Common Substring II (SAM - 两串求最长公共子串 (lcs))

看到求 \(\text{lcs}\),考虑建 SAM

先考虑两个串 \(s, t\) 怎么做

\(s\) 建 SAM,遍历 \(t\) 放到 SAM 中查询

设当前遍历到 \(t_i\);考虑维护 \(t_{[1, i]}\) 在 SAM 上的匹配位置 \(u\) 以及匹配长度 \(l\),设 \(t_{[1, i-1]}\) 的相关信息为 \(u'\)\(l'\)

  • \(\delta(u', t_i)\) 存在,则令 \(u = \delta(u', t_i)\)\(l = l'+1\)
  • \(\delta(u', t_i)\) 不存在,考虑类似建 SAM 时插入字符的思想,跳 \(\text{link}\) 直到 \(\delta(u', t_i)\) 存在:
    • 若跳完 \(\text{link}\) 也没有找到使 \(\delta(u', t_i)\) 存在的 \(u'\),令 \(u = \text{rt}\)\(l = 0\)

    • 反之,令 \(u = \delta(u', t_i)\)\(l = \text{len}(u')+1\)

      对任意节点 \(i\),都有 \(i\) 代表的 \(\text{endpos}\) 等价类中最短子串长度 \(>\) \(\text{len}(\text{link}(i))\)

      因此,跳 \(\text{link}\)\(\text{len}(u')+1\) 必然是能取到的

那么我们在每个点记录最长匹配长度即可

对多个串,考虑对最短串建 SAM,枚举每个串做两个串的匹配

我们在 SAM 上每个节点记录当前轮最长匹配长度 \(w_i\),历史匹配最小值 \(\text{mn}_i\)

每轮匹配结束后,令 \(\text{mn}_i \leftarrow \min\{\text{mn}_i, w_i\}\);最终 \(\max\{\text{mn}_i\}\) 即为答案

注意,若 SAM 上的节点 \(i\) 匹配,\(\text{parent tree}\)\(i\) 的每个祖先也都能匹配:

  • 在两个串匹配时,选祖先匹配肯定不如选自己匹配优,因此可以不管

  • 在多个串匹配时,由于需要对历史匹配最小值取 \(\min\),选自己不一定优

    因此,我们记录每个点当前轮的最长匹配长度 \(w_i\),在匹配结束后遍历 \(\text{parent tree}\) 更新即可

    具体的,设 \(v \in \text{son}(u)\),若 \(w_v > 0\),则令 \(w_u \leftarrow \max(w_u, \text{len}(u)+1)\)

事实上,每次需要遍历 \(\text{parent tree}\) 更新正是我们选择最短串建 SAM 的原因

时间复杂度 \(O(\sum |s_i|)\)

CF1054F - Electric Scheme (二分图求最大独立集方案 - 布尔变量赋值法)

首先显然有解,在每个火花 \((x_i, y_i)\) 处画两次 \((x_i, y_i, x_i, y_i)\) 即可

注意到可以将连一根长线拆成很多相邻的短线,于是考虑将火花按分别按 \(x, y\) 坐标排序,相邻火花间连线

令初始时答案为 \(2n\),我们可以选择合并一些线,每次合并答案会 \(-1\),求最多能合并多少次

显然,有冲突关系的线 (相交且不交于端点) 我们只能选 \(1\) 根;考虑直接在线间连边刻画冲突关系

问题转化为对于点数为 \(O(n)\),边数为 \(O(n^2)\) 的二分图求最大独立集方案

考虑布尔变量赋值法:

  • 给每个点赋布尔变量 \(x_i\),以最小割为例,令 \(x_S = 1, x_T = 0\)

    \(x_i = 1\)\(i\) 属于 \(S\) 连通块,\(x_i = 0\) 则属于 \(T\) 连通块

    则最小割可转化为最小化 \(\displaystyle \sum_{(u_i \rightarrow v_i, w_i) \in E} w_ix_{u_i}(1-x_{v_i})\)

  • 类似的,令 \(x_i = 1\) 表示选择点 \(i\)\(x_i = 0\) 表示不选

    则最大独立集可转化为最小化 \(\displaystyle \sum_{u \in V} -x_u + \sum_{(u_i, v_i) \in E} \infty x_{u_i}x_{v_i}\)

    考虑将最大独立集的式子转化为最小割的式子

    注意到 \(\infty x_{u_i}x_{v_i}\) 不好处理,我们希望将 \(x_{v_i}\) 变为 \((1-x_{v_i})\);由于原图为二分图,可以将所有右部点取反

    具体的,对右部点,更改定义为 \(x_i = 1\) 表示不选点 \(i\)\(x_i = 0\) 表示选;原式转化为:

    \(\displaystyle \sum_{u \in L} -x_u + \sum_{v \in R} -(1-x_v) + \sum_{(u_i, v_i) \in E} \infty x_{u_i}(1-x_{v_i})\)

    \(\displaystyle = \sum_{u \in L} -x_u + \sum_{v \in R} x_v + \sum_{(u_i, v_i) \in E} \infty x_{u_i}(1-x_{v_i}) - |R|\)

    考虑将 \(-x_u\)\(x_v\) 也转化为 \(x_{u_i}(1-x_{v_i})\) 的形式,注意到 \(x_S = 1, x_T = 0\),转化为:

    \(\displaystyle = \sum_{u \in L} x_S(1-x_u) + \sum_{v \in R} x_v(1-x_T) + \sum_{(u_i, v_i) \in E} \infty x_{u_i}(1-x_{v_i}) - |L| - |R|\)

    常量扔掉,直接建模最小割即可:

    • \(u \in L\),连边 \((S \rightarrow u, 1)\)

    • \(v \in R\),连边 \((v \rightarrow T, 1)\)

    • \((u_i, v_i) \in E\),连边 \((u_i \rightarrow v_i, \infty)\)

      事实上,易得这部分每条边流量最大为 \(1\),可以直接将容量改为 \(1\),这样 dinic 是 \(O(m \sqrt n)\)

那么直接 dinic 即可

跑完后 dfs 搜出 \(S\) 的联通块,最大独立集方案即为:

  • 满足 \(u_i \in L\)\(x_{u_i} = 1\) (在 \(S\) 的连通块) 的 \(u_i\)
  • 满足 \(v_i \in R\)\(x_{v_i} = 0\) (在 \(T\) 的连通块) 的 \(v_i\)

时间复杂度 \(O(n^2 \sqrt n)\)

8.28

CF1416F - Showing Off (拆环 + 二分图 - 关键点优先匹配)

对位置 \((x, y)\),若存在相邻位置 \((x', y')\) 满足 \(b_{x', y'} < b_{x, y}\),则可让 \((x, y)\) 走到 \((x', y')\),再用 \(a_{x, y}\) 补齐差值

显然,若对所有相邻位置都有 \(b_{x', y'} > b_{x, y}\),则无解

那么难点只在于处理 \(b_{x', y'} = b_{x, y}\) 的情况;这实际上要求 \((x, y)\)\((x', y')\) 在一个环内

注意到环长必为偶数,考虑拆成许多二元环处理,而二元环就相当于两两匹配

问题转化为将满足 \(b_{x', y'} = b_{x, y}\)\((x', y')\)\((x, y)\) 连边,求最大匹配方案

但事实上,有些 \((x, y)\) 已经可以连到相邻且小于它的位置,这种位置匹配不上也没关系

我们称必须匹配的点为 "关键点",则我们需要让关键点优先匹配

有的先匹配有的后匹配做不了,考虑通过 "让非关键点匹配机会变多" 降低其 "匹配优先级",具体的:

  • 创建一些 "幻想点" 将左右部点数量补齐

  • 在所有不是关键点的点 (即 "非关键点" 与 "幻想点") 间两两连边

    这一步可以创建一个虚点优化建图

跑最大匹配,若不是完美匹配则无解,若是则搜出方案即可

时间复杂度 \(O(nm \sqrt{nm})\)

QOJ3555 - Chameleon's Love (观察性质 + 二分图独立集)

部分分 1:所有恋慕关系都是双向的

若选择相互恋慕的一对变色龙,它们会互相交换颜色,不改变颜色总数 (即颜色总数 \(=\) 询问集合大小)

那么颜色总数改变 \(\iff\) 选择了至少一对颜色相同的变色龙

考虑对每个变色龙 \(i\) 二分一次,\(i\)\(S\) 中的点有连边 \(\iff\) \(\text{Query}(S \cup i) > \text{Query}(S)\)

询问次数 \(O(n \log n)\)

这个部分分启示我们观察什么时候颜色总数会改变

部分分 2\(O(n^2)\) 次询问

考虑对每两只变色龙都问一次,若颜色总数为 \(1\) 则连边

对变色龙 \(i\),设 \(a_i\)\(i\) 恋慕的变色龙,\(b_i\) 为恋慕 \(i\) 的变色龙,\(c_i\) 为与 \(i\) 同色的变色龙

显然,\(i\) 只可能和 \(a_i, b_i, c_i\) 连边

\(i\) 的度数为 \(1\),则必有 \(a_i = b_i\),此时 \(i\) 连向的点就是 \(c_i\)

\(i\) 的度数为 \(3\),考虑分讨询问 \(\{i, a_i, b_i, c_i\}\) 子集的情况:

  • \(\{i, a_i, b_i, c_i\}\),则 \(i \rightarrow a_i\)\(b_i \rightarrow i\)\(i = c_i\),颜色总数为 \(2\)
  • \(\{i, a_i, b_i\}\),则 \(i \rightarrow a_i\)\(b_i \rightarrow i\),颜色总数为 \(2\)
  • \(\{i, b_i, c_i\}\),则 \(b_i \rightarrow i\)\(i = c_i\),颜色总数为 \(1\)
  • \(\{i, a_i, c_i\}\),则 \(i \rightarrow a_i\),颜色总数为 \(2\)
  • \(\{i, a_i\}\)\(\{i, b_i\}\)\(\{i, c_i\}\) 颜色总数均为 \(1\)

容易发现情况 \(\{i, b_i, c_i\}\) 是特殊的,找出这种情况后将所有 \(i \rightarrow a_i\) 拿出来,用排除法找出 \(c_i\) 即可

询问次数 \(O(n^2)\)

这个部分分启示我们重点关注 \(a_i, b_i, c_i\)

部分分 3:性别已知

在部分分 2 的基础上,我们只需优化询问次数即可

对变色龙 \(i\),考虑找与其性别不同的变色龙组成的集合 \(S\) 询问

有了部分分 2 的启发,容易发现只有 \(a_i, b_i, c_i\) 至少一个在 \(S\) 中时,颜色总数改变

那么可以通过 \(3\) 次二分找出 \(a_i, b_i, c_i\),剩下的与部分分 2 相同

询问次数 \(O(n \log n)\)

正解

考虑优化部分分 3 的做法

注意到我们实际上不需要 \(S\) 中性别均相同,只需要 \(S\) 内部无连边即可

这启示我们维护二分图独立集

考虑增量构造,维护两个独立集 \(S_0, S_1\),每次加入新节点 \(i\)

容易通过部分分 3 的方式对 \(S_0\)\(S_1\) 分别询问,二分出 \(i\)\(S_0, S_1\) 中的点的所有连边

由于 \(n \le 500\),直接连无向边,重新黑白染色构造出新的 \(S_0, S_1\) 即可

最终找到所有连边后,可用部分分 2 的做法求出答案

询问次数 \(O(n \log n)\),时间复杂度 \(O(n^2 \log n)\)

posted @ 2025-07-13 18:49  lzlqwq  阅读(21)  评论(0)    收藏  举报