2025.9 做题记录
2025.9 做题记录
9.1 - 9.3
网课 + 补暑假作业 + 摆烂
但是再不努力就没有机会了。
9.4
QOJ7999 拉丁方 (二分图边染色)
部分分:\(C = n\)
考虑将每列缩成一个点,若列与数字不冲突则在列与数字间连边;显然会形成一个左部点为列,右部点为数字的二分图
现在我们希望进行 \(n-R\) 次操作,每次找到一组完美匹配并删去
首先考虑是否有解:
-
容易发现,左部点的度数均为 \(n-R\);每个数字在上面 \(R \times n\) 的矩阵中恰出现 \(R\) 次,右部点的度数也均为 \(n-R\)
对于每个点度数均为 \(k\) 的图,我们称为 \(k\) - 正则图
-
对于 \(k\) - 正则图,由 Hall 定理,必存在一组完美匹配
-
将完美匹配删去,会形成 \(k-1\) - 正则图;那么归纳可得必存在 \(k\) 组完美匹配
综上,原问题有解
考虑如何解决原问题:
-
事实上,这是二分图边染色问题
我们需要给二分图中的每条边染色,使得同色边不共顶点
-
有结论:记最大度数为 \(\text{deg}\),则最少只需 \(\text{deg}\) 种颜色即可
显然,顶点的每条出边颜色不能相同,\(\text{deg}\) 是答案的下界
接下来考虑给出构造
考虑依次加入每条边;设当前加入 \((u, v)\),我们维护每个顶点已染出边颜色的 \(\text{mex}\):
-
若 \(\text{mex}_u = \text{mex}_v\),则将 \((u, v)\) 染成 \(\text{mex}_u\) 即可
-
反之,令 \((u, v)\) 的颜色为 \(\text{mex}_u\)
若 \(v\) 已有颜色为 \(\text{mex}_u\) 的出边,记为 \((v, v')\),考虑将 \((v, v')\) 的颜色调整为 \(\text{mex}_v\)
若 \(v'\) 之前已有颜色为 \(\text{mex}_v\) 的出边,记为 \((v', v'')\),考虑将 \((v', v'')\) 的颜色调整为 \(\text{mex}_u\)
若 \(v''\) 之前已有颜色为 \(\text{mex}_u\) 的出边,记为 \((v'', v''')\),考虑将 \((v'', v''')\) 的颜色调整为 \(\text{mex}_v\)
综上,类似增广路,依次将冲突边的颜色调整为 \(\text{mex}_u, \text{mex}_v, \text{mex}_u, \text{mex}_v, \cdots\)
容易证明,最终不会调整回 \(u\)
由于我们总是照着 \(\text{mex}\) 调整的,最终答案不会超过 \(\text{deg}\);证毕
-
那么直接模拟二分图边染色即可;单次最劣时间复杂度 \(O(n^3)\)
接下来考虑原问题
部分分启示我们先填上面的 \(R \times (n-C)\),再填剩下的 \((n-R) \times n\)
对于上面的部分,将行与数字连边,容易发现仍为二分图边染色
但此时整个二分图不是 \(k\) - 正则图,令最大度数为 \(\text{deg}\):
- 若 \(\text{deg} = n-C\),直接二分图边染色即可
- 若 \(\text{deg} > n-C\),所需颜色数必然 \(>n-C\),无法找出 \(n-C\) 组最大匹配,无解
判掉无解的情况后跑两次二分图边染色即可;总时间复杂度 \(O(Tn^3)\),实际上跑不满
实现时可能需要对加边顺序 random_shuffle 防止被卡满
9.5
P3623 [APIO2008] 免费道路 (最小生成树 - 限制特殊边数量)
以下称"鹅卵石路"为"黑边","水泥路"为"白边"
注意到对所有黑边,有些是必连的 (否则不连通),有些是可连可不连的
考虑先求出必连边
先将所有白边加上,跑一遍 Kruskal,此时选中的黑边即为必连边
容易发现若有多条黑边满足要求,随便选不影响答案
考虑确定可连可不连的边
将必连边都连上后跑 Kruskal,优先连黑边,直到连够 \(K\) 条为止
无解情况:图不连通 / 必连边个数 \(>K\) / 按如上方式构造出的最终方案中黑边个数 \(<K\)
时间复杂度 \(O(\alpha m)\)
9.6
摆烂 + 补 whk
9.7
模拟赛
9.7 T1 - CF1527D - MEX Tree (往大容斥 + 分讨)
看到这个形式,首先考虑容斥
注意到往小容斥 (转化为 \([\text{mex} \le k]-[\text{mex} \le k-1]\) ) 是不好做的,考虑往大容斥
对于 \([\text{mex} > k]\),相当于强制加入点 \(0 \sim k\),再随意选点形成路径
从小到大依次加入点 \(0 \sim n\),考虑维护路径端点 \(u, v\)
只需分讨两端点是否有祖先关系即可;若加入点后无法形成路径,则后面的答案都是 \(0\)
时间复杂度 \(O(n \log n)\)
反思:
-
场上在往小容斥的思路里陷的太深了,花了 1h 才意识到往大容斥直接做完了,以后应该两种方向都想下
需要锻炼做简单题的速度,1h30min 才切 T1 根本没可能切出 T3, T4,只能拿大众分
9.7 T2 - CF1497E2 - Square-free division (hard version) (DP 优化 - 先枚举值域小维 + 贪心选择转移区间 + 消平方因子)
首先显然有 \(O(n^2k)\) 的 DP
令 \(f_{i, j}\) 表示到第 \(i\) 位用了 \(j\) 次修改,能划分出的最少连续段数
转移为 \(f_{i, j} \leftarrow f_{k, j-w(k+1, i)}\),其中 \(w(l, r)\) 表示将 \(a_{[l, r]}\) 改到合法的最小修改次数
考虑如何求出 \(w(l, r)\)
对于一次修改,我们可以把一个数改成极大质数,使其不与任何数冲突
将区间内的冲突关系连边,容易发现形成了很多完全图;对大小为 \(siz\) 的完全图,只需改 \(siz-1\) 次即可
由于是完全图,只需维护每个点向前 / 向后的第一次连边即可
\(O(n^2)\) 预处理出 \(w(l, r)\),DP 转移是 \(O(n^2k)\) 的
考虑对 DP 进行优化
对于 \(O(n^2k)\) 的转移,问题在于我们每次先枚举上个区间的结束位置 \(k\);注意到第二维值域是 \(K\),考虑先枚举第二维
具体的,钦定 \(w(l, r) = v\),我们先枚举 \(v\);有一个显然但重要的性质是若 \(r, v\) 确定,\(l\) 越靠前越好
因此,转移区间只有 \(K\) 个,直接转移是 \(O(nk^2)\) 的,可以接受
现在的问题是如何求出 \(l_{r, v}\),表示最靠前的使得 \(w(l, r) = v\) 的 \(l\)
一切的基础在于,我们需要先求出每个点向前 / 向后的第一次连边
一个常见的 Trick 是消平方因子,消完后 \(a_l, a_r\) 有连边等价于 \(a_l = a_r\)
一种想法是线段树上二分
具体的,从左往右扫,设当前扫到 \(i\),其向前的第一次连边是 \((\text{ls}_i, i)\),将 \([1, \text{ls}_i]\) 区间加 \(1\)
枚举 \(v\),线段树上二分左端点即可;时间复杂度 \(O(nk \log n)\)
更厉害的做法是,你注意到当 \(v\) 不变且 \(r\) 变大时,\(l_{r, v}\) 也会变大,换句话说是有单调性的
那么直接双指针即可;时间复杂度 \(O(nk)\)
综上,预处理时间复杂度 \(O(nk)\),DP 时间复杂度 \(O(nk^2)\),可以通过
反思:
-
对于 \(f_{i, j} \leftarrow f_{k, j-w(j+1, i)}\) 这种类划分区间转移,当第二维值域较小,可以考虑先枚举第二维 + 观察性质以优化复杂度
需要注意不能在贪心上陷太久;动态维护最多覆盖位置一般是没啥道理的
-
已经做过的 Trick 不应该想不起来的;尤其是忘记了消平方因子,第一步不会啥都没法做了
9.7 T3 - CF1536F - Omkar and Akmar (观察性质)
诈骗题
注意到 A 与 B 必然成对出现,由于是环,最后必然进行偶数步
因此显然有后手必胜,且不管怎么填都没事
那么问题转化为对合法游戏过程计数
枚举空格数 \(i\),显然不能有 \(\ge 2\) 个空格相邻,考虑插板法
将 \(n-i\) 个数字排成一排,首尾的空是相同的,方案数为 \(\binom{n-i}{i}\);乘上将数字填进去的圆排列数,即 \(\times (n-i-1)!\)
每个空有 ABA... 与 BAB... 两种填法,需要 \(\times 2\);环上可以随意旋转,需要 \(\times n\)
那么最终式子即为 \(\displaystyle 2n \sum_{i = n \bmod 2, i \leftarrow i+2}^{\lfloor \frac{n}{2} \rfloor} \binom{n-i}{i} (n-i-1)!\)
反思:All you need is attention
9.7 T4 - 牛客多校 - Diameter Counting (DP - 直径转中点中边)
题意:求大小为 \(n\) 的所有带标号无根树的直径的和,答案对 \(P\) 取模
\(n \le 500\),\(10^8 \le P < 2^{31}\)
考虑直径的性质:长为奇数的直径都交于直径中边,长为偶数的直径都交于直径中点;考虑以中边 / 中点为根
因此,只需计数点数与最大深度固定的有标号有根树即可;考虑容斥解决
令 \(f_{i, j}\) 表示 \(i\) 个点,最大深度 (点数) \(\le j\) 的有标号有根树的数量
这里之所以用点数,是因为若用边数,不好区分没有点和只有一个点的情况
为方便转移,再令 \(g_{i, j}\) 表示 \(i\) 个点,最大深度 (点数) \(\le j\) 的有标号叶向森林的数量;特别的,只有一棵树也合法
考虑 \(f_{i, j}\) 与 \(g_{i, j}\) 如何转移
对 \(f_{i, j}\),显然有 \(f_{i, j} \leftarrow g_{i-1, j-1} \times i\),表示选定一个根
对 \(g_{i, j}\),考虑枚举一个子树拼到森林中;但直接转移显然会算重
这里有个 Trick,我们钦定标号最小点必定在靠前的子树中,只重新分配剩余的 \(i-1\) 个标号,这样就能够避免算重
具体的,有转移 \(\displaystyle g_{i, j} \leftarrow \sum_{k=1}^{i} \binom{i-1}{k-1} f_{k, j} g_{i-k, j}\);枚举到 \(i\) 是因为单独一棵树也有贡献
对 \(f_{i, j}\) 与 \(g_{i, j}\) 进行差分,差分数组记为 \(cf_{i, j}\) 与 \(cg_{i, j}\),表示深度固定时的答案
考虑枚举直径长度 (边数) \(d\),按奇偶分类讨论:
-
\(d\) 为奇数,此时以边为根,两边连接两个子树;枚举子树大小即可
贡献为 \(\displaystyle d \sum_{i=1}^{n-1} \binom{n-1}{i-1} cf_{i, \frac{d}{2}+1} cf_{n-i, \frac{d}{2}+1}\)
-
\(d\) 为偶数,此时以点为根,可连接多个子树,限制至少两个子树的最大深度为 \(\frac{d}{2}\)
考虑用 \((cg_{n-1, \frac{d}{2}}-cf_{n-1, \frac{d}{2}}) \times n\),森林 (不能是一棵树) + 选定根解决
但这个式子的意义是每棵子树的深度都是 \(\frac{d}{2}\);我们只要求至少两棵是 \(\frac{d}{2}\),因此考虑容斥解决
具体的,先用 \((g_{n-1, \frac{d}{2}}-f_{n-1, \frac{d}{2}})-(g_{n-1, \frac{d}{2}-1}-f_{n-1, \frac{d}{2}-1})\) 算出有的深度是 \(\frac{d}{2}\),有的是 \(\frac{d}{2}-1\) 的数量
考虑再减去只有一棵深度为 \(\frac{d}{2}\) 的数量
强行钦定一棵子树深度为 \(\frac{d}{2}\),方案数为 \(\displaystyle \sum_{i=1}^{n-2} \binom{n-1}{i} cf_{i, \frac{d}{2}} cg_{n-1-i, \frac{d}{2}-1}\)
注意,这里组合数是 \(\binom{n-1}{i}\) 而非 \(\binom{n-2}{i-1}\),因为此处将特殊子树插到哪里都行,不需要钦定一定在最前面
那么总式子为 \(nd \times [(g_{n-1, \frac{d}{2}}-f_{n-1, \frac{d}{2}})-(g_{n-1, \frac{d}{2}-1}-f_{n-1, \frac{d}{2}-1})-\displaystyle \sum_{i=1}^{n-2} \binom{n-1}{i} cf_{i, \frac{d}{2}} cg_{n-1-i, \frac{d}{2}-1}]\)
此处多乘 \(n\) 是因为还需要钦定根
时间复杂度 \(O(n^3)\);轻微卡常,精细实现取模与枚举上下界就能过
实现时注意:
- 没有保证 \(P\) 是质数,不能用阶乘 + 逆元的方式求组合数,写递推即可
- 根据实现不同,可能需要在转移式中的一些地方让第二维对第一维取 \(\min\)
反思:
- 统计直径时考虑转化为以直径中点 + 直径中边为根,再对树 / 森林计数
- 想清楚细节再写!手玩小数据确实是很好的检查细节的办法
9.9
CF888G - Xor-MST (最小生成树 - B + 01Trie 分治)
法 1
对于完全图生成树,考虑 Boruvka
现在的问题是如何快速求出一个连通块 \(S\) 向外部点的最小连边
对于异或,考虑 01 Trie
维护连通块的 Trie 与全局 Trie,对每个点维护 \(\text{siz}\),合并时枚举连通块内每个点,在全局字典树中将 \(\text{siz}\) 对位减后查询即可
时间复杂度 \(O(n \log n \log V)\)
法 2
考虑分治,每次将当前点集 \(S\) 分为两个集合 \(L, R\),递归处理 \(L, R\),再在两个点集中各选一点连边
分治时传参数 \(\text{bit}\),每层分治按当前数的第 \(\text{bit}\) 位分类
正确性证明:
-
若将 \(0\) 集合中的点 \(a_i\) 放入 \(1\) 集合 (反过来同理):
- 若 \(a_i\) 向 \(0\) 集合连边,本质上与 \(a_i\) 本来就在 \(0\) 集合没有区别
- 反之,则此时代价至少为 \(2 \times 2^{\text{bit}} = 2^{\text{bit}+1}\) ( \(1\) 集合内向 \(a_i\) 连,\(1\) 集合内向 \(0\) 集合连)
-
若不将 \(0\) 集合中的点放入 \(1\) 集合,当前层代价为 \(2^{\text{bit}}\) ( \(1\) 集合内向 \(0\) 集合连)
类似的,往下分治后的代价最大为 \(2^0 + 2^1 + \cdots + 2^{\text{bit}-1}\)
那么总代价为 \(2^0 + 2^1 + \cdots + 2^{\text{bit}} = 2^{\text{bit}+1}-1\)
综上,\(2^{\text{bit}+1}-1 < 2^{\text{bit}}\),证毕
实现时,先递归左侧,递归不下去时将当前数插入 Trie 中,再枚举右侧点放在 Trie 中查询;最后递归右侧即可
时间复杂度 \(O(n \log n \log V)\)
CF1305G - Kuroni and Antihype (刻画答案 + 建虚点 + 重标边权 + 最小生成树 - 枚举边权)
将邀请关系连有向边,容易发现形成了多个 DAG;此时答案为 \(\displaystyle \sum_{u} a_u \text{out}_u\)
建立点 \(n+1\),满足 \(a_{n+1} = 0\);对所有通过方式 \(1\) 加入的点 \(u\) 连边 \(n+1 \rightarrow u\);这样保证最终只有一个 DAG
DAG 是不好办的,我们希望将有向边转为无向;注意到一个点入度最多为 \(1\),考虑重赋边权
将 \((u, v)\) 的边权重置为 \(a_u+a_v\),最终再减去 \(\displaystyle \sum_{u} a_u\) 即可;此时形成了树
那么我们只需求解最大生成树即可
枚举边时间复杂度无法接受;注意到同边权的边会连很多条,考虑 Kruskal,转为枚举最大边权 \(w\)
对于边 \((u, v, w)\),必然有 \(a_u\) 与 \(a_v\) 按位与为 \(0\);因此加可转化为按位或,一个很好的性质是 \(a_v = w \oplus a_u\)
综上,枚举 \(w\),再枚举 \(w\) 的子集 \(u\),维护相同值的连通块个数 \(\text{cnt}_u\),合并 \(u\) 与 \(w \oplus u\)
具体的,合并 \(w, u, v\) ( \(w \oplus u = v\) ) 时,贡献为 \(w \times (\text{cnt}_{\text{fa}_u}+\text{cnt}_{\text{fa}_v}-1)\);合并后的新连通块的根的 \(\text{cnt} = 1\)
时间复杂度 \(O(3^{\log V} \alpha(n))\)
9.10
做 P3206 [HNOI2010] 城市建设,但是没调出来
9.11
P3206 [HNOI2010] 城市建设 (cdq / 线段树分治 + 观察性质 + 可撤销并查集)
对于永久修改操作,考虑 cdq / 线段树分治动态转静态,两者本质相同,此处以 cdq 为例
令当前分治区间为 \([l, r]\),表示求解前 \(i\ (i \in [l, r])\) 个操作的答案
称操作 \([l, r]\) 中修改的边为 "动态边",其余边为 "静态边"
记 \(\text{len} = r-l+1\),我们希望将每层 cdq 的复杂度控制在 \(O(\text{len} \log \text{len})\) 以内
考虑观察性质:
- 若强制不连动态边,跑最小生成树,此时仍不在最小生成树中的边肯定用不到,可以扔掉
- 若强制连动态边,跑最小生成树,此时仍在最小生成树中的边肯定会用到,可以直接缩起来
因此,考虑在每层维护可能用到的静态边集合 \(S\)
当往 \([l, \text{mid}]\) 递归时,流程如下:
-
令 \([\text{mid}+1, r]\) 为静态边 (若与 \([l, \text{mid}]\) 中的边冲突则扔掉),加入集合 \(S\)
-
对 \(S\) 跑 Kruskal,记最小生成树边集为 \(T\),令 \(S \leftarrow T\);最后将并查集撤销回初始状态
-
将 \([l, \text{mid}]\) 这些动态边缩起来,再对 \(S\) 跑 Kruskal,记最小生成树边集为 \(T\);将并查集撤销回初始状态
将 \(T\) 中的边直接缩起来,更新答案,递归 \([l, \text{mid}]\);回溯时记得把答案减回来、并查集撤回来
-
当要求解 \([\text{mid}+1, r]\) 时,\([l, \text{mid}]\) 的边已经成为了静态边
对于这些边,若不与 \([\text{mid+1}, r]\) 中的边冲突,则要加入 \(S\) 中
-
同理,进行删无用静态边、缩必需静态边的操作,更新答案,递归 \([\text{mid}+1, r]\);回溯时同样减答案、撤并查集
边界为 \(l = r\) 时,设当前动态边为 \((u, v)\):
-
若 \(u, v\) 已经连通,只需更新当前边最新权即可
-
若 \(u, v\) 不连通,则可选择连动态边 / 连 \(S\) 中的一条边
在两种情况中取 \(\min\) 并更新答案,同时更新当前边最新权即可
初始时,静态边集为未被修改操作覆盖的边;我们需要先进行一次删无用静态边、缩必需静态边并更新答案的操作
实现时需要维护一个全局可撤销并查集:
-
设 \(\text{merge}\) 操作为 \(\text{siz}_u \leftarrow \text{siz}_u + \text{siz}_v\) 且 \(\text{fa}_v = u\)
开一个栈,在 \(\text{merge}\) 时记录修改信息,即 \(v, \text{siz}_v\)
-
在撤销时,令 \(\text{siz}_{\text{fa}_v} \leftarrow \text{siz}_{\text{fa}_v}-\text{siz}_v\) 且 \(\text{fa}_v = v\) 即可
-
注意,可撤销并查集不能路径压缩 (不然不好撤销),只能按秩合并
时间复杂度 \(O(n \log^2 n)\)
实现时可能需要特判重边
9.12
P9531 [JOISC 2022] 复兴计划 (MST - 观察绝对值函数性质 + 拆贡献)
题意:给定无向连通图,边有边权,多次询问给定 \(x\),边权修改为 \(|w-x|\) 时的最小生成树边权和
\(n \le 500\),\(m \le 10^5\),\(q \le 10^6\)
考虑观察绝对值函数的性质
将所有 \(f_i(x) = |w_i-x|\) 画在平面直角坐标系中,会形成许多 V 形
9.13
摆烂 + 补 whk
9.14
模拟赛
9.14 T1 - 猜数 (数位 DP - 两位两位填)
考虑数位 DP
传统数位 DP 是一位一位确定的,注意到此处因为有 "翻转",前后两位相互对应,考虑两位两位的填
注意到位数对对应关系有影响,不过设 \(z\) 的位数为 \(\text{cnt}\),填的数只能为 \(\text{cnt}\) 位或 \(\text{cnt}-1\) 位,分别处理即可
由于是加法,进位最多只有 \(1\),考虑在状态中维护高低两处的进位
具体的,令 \(f_{i, 0/1, 0/1}\) 表示从前往后考虑到 \(a_i, a_{cnt-i+1}\) 这对数,高侧是否有向高的进位,低侧是否有从低进过来的位
转移时,将相加后两处的值写出来,枚举两位分别填的数 check 一下即可
边界条件为填到中心时,根据奇偶分讨,枚举两数 check 即可
细节上,注意可能有 \(9+1 \rightarrow 0\) 的情况,以及第一位不能填前导 \(0\)
时间复杂度 \(O(4T \log V)\)
反思:想清楚细节,优先找简单的方式实现,不要写着写着又推翻重写;做这种简单题的速度需要加强
9.14 T2 - 排序 (序列转环 + DS)
法 1
注意到,题目描述的排序过程实际上是不断找出未排好序的数的最大值,并换到最前面
这启示我们对每轮的最大值拆贡献
设当前最大值为 \(\text{mx}\),易得每次会将 \(\text{mx}\) 前未排好序的部分整体平移至序列最后 (不改变相对顺序)
考虑平衡树维护平移 + 查最大值 + 删数
具体的,对平移操作,考虑按 siz 分裂后交换左右儿子
对查最大值的操作,考虑线段树的思想,自底向上 pushup
时间复杂度 \(O(n \log n)\)
法 2
注意到,整体平移等价于在环上操作
那么我们只需维护在环上跳最大值的过程
一种想法是用线段树维护最大值 + 区间内未删的数的个数,时间复杂度 \(O(n \log n)\)
事实上,用线段树维护最大值是不必要的,因为我们每个数都会跳到
离散化后开 vector 记录每个数的出现位置,切换 vector 时二分即可
那么只需支持单点打 tag + 区间查打 tag 点的个数 (单点改区间查),树状数组即可
时间复杂度 \(O(n \log n)\),常数较小
反思:
- 序列转环的 trick 需要积累
- 平衡树是可以同时支持下标相关 + 值相关操作的,只不过不能直接按值分裂,需要用线段树的思想
- 即使是非常小的转化也要先确认正确性,最好不要凭直觉;赛时因为第一步的错误转化浪费了大量时间
9.14 T3 - 水池 (笛卡尔树 + 贪心 - 每次选最优叶子)
将每个横线看成点,为保证高度连续,按其 \(y\) 坐标建笛卡尔树
设点 \(i\) 对应横线的宽度为 \(\text{wid}_i\),高度为 \(h_i\)
那么点 \(i\) 相对其父亲 \(\text{fa}_i\) 能多积的水量就是 \(\text{wid}_i \times (h_i-h_{\text{fa}_i})\),记为 \(w_i\)
首先考虑 \(k = 1\),即我们需要选择一个叶子
容易发现叶子 \(u\) 的贡献为其到根链上的 \(w_i\) 之和,记为 \(\text{dis}_u\);那么答案即为 \(\max \text{dis}_u\)
考虑解决原问题
\(k = 1\) 的情况启示我们,每次选择 \(\text{dis}_u\) 最大的叶子,刨去其对其他叶子的影响,重复 \(k\) 次即可
证明需要用到闵可夫斯基和;暂时咕咕咕
注意到每个点只会被清零一次,考虑每次暴力跳父亲,将链改转化为子树改;线段树维护即可
时间复杂度 \(O(n + k \log n)\)
反思:All you need is attention
9.14 T4 - 连线 (卡特兰数 + 括号树 + 树形 DP - 维护总覆盖长度)
先考虑 \(k = 0\) 的部分分
设 \(f_i\) 表示 \(i\) 个点的连线方案
转移时枚举第 \(i\) 个点向前连到哪个点,即 \(f_i \leftarrow f_{j-1} \times f_{i-j-1}\)
注意到这就是卡特兰数,记为 \(H_n\);对 \(n\) 个点的情况,若 \(n\) 为奇数则答案为 \(0\),反之为 \(H_{\frac{n}{2}}\),以下记为 \(C_n\)
从简单情况入手,考虑 \(k=1\) 的情况
若擦掉红线,贡献为 \(C_n\)
反之,考虑将红线两侧的点拼起来,再乘上红线内部点的贡献;记红线覆盖了 \(\text{len}\) 个点 (包括端点),贡献为 \(C_{n-\text{len}} \times C_{\text{len}-2}\)
考虑将其推广到 \(k\) 条互不相交的红线的情况
设第 \(i\) 条红线覆盖 \(\text{len}_i\) 个点
若留下的红线集合为 \(S\),贡献即为 \(C_{n-\sum_{i \in S} \text{len}_i} \times \prod_{i \in S} (\text{len}_i-2)\)
连乘部分可以拆到每次选择红线时计算,我们只关心 \(\sum_{i \in S} \text{len}_i\)
这启示我们将它刻画到 DP 状态中
考虑解决原问题
建出红线对应的括号森林 (区间完全包含则连边),考虑树形 DP
令 \(f_{u, x}\) 表示点 \(u\) 子树中上式为 \(x\) 的方案数,\(\text{len}_u\) 表示 \(u\) 对应括号的长度
对 \(u\) 内部小括号的贡献,有转移 \(f_{u, x} \leftarrow f_{u, k} \times f_{v, x-k}\ (v \in \text{son}_u)\),即树上背包
对外侧大括号内未被覆盖的点的贡献,有转移 \(f_{u, \text{len}_u} \leftarrow f_{u, i} \times C_{\text{len}_u-2-i}\)
为方便统计答案,设存在一个编号为 \(0\),覆盖 \([0, n+1]\) 的括号,作为括号树的根
答案即为 \(\sum_{i = 0}^{n} f_{0, i} \times C_{n-i}\);初始值为对每个点 \(u\),有 \(f_{u, 0} = 1\)
时间复杂度 \(O(n^2)\)
反思:由部分分推性质,逐步思考正解
9.15
P2934 [USACO09JAN] Safe Travel G (最短路树 + 树剖)
由于最短路唯一,考虑建出最短路树;最后即询问对每个点 \(u\),断掉 \((u, \text{fa}_u)\) 后的最短路长度
显然,选两条非树边是不优的
枚举每条非树边 \((u_i, v_i, w_i)\),考虑其对树上节点答案的影响
事实上,这条非树边只会影响满足如下条件的点:
- 在 \(u_i\) 或 \(v_i\) 的到根链中
- 子树中不同时包含 \(u_i\) 与 \(v_i\)
对点 \(k\),该条边的贡献为 \(\text{dis}_{u_i}+\text{dis}_{v_i}+w_i-\text{dis}_k\)
注意到 \(\text{dis}_{u_i}+\text{dis}_{v_i}+w_i\) 与点的信息无关,设为 \(W_i\)
那么对点 \(k\),答案即为 \(-\text{dis}_k+\min W_i\)
树剖维护即可,时间复杂度 \(O(m \log^2 n)\)
P5100 [JOI 2017 Final] 足球 / Soccer (观察性质 + 拆点建图)
首先,一名球员必只在一段区间中控球,不可能传出去又接回来 (不然不如自己控球到对应位置)
因此,当球落地,我们总是会让离球最近的人去接
将每个位置拆成三个点,分别代表球落地 / 前后飞 / 左右飞,以下记为 \((x, y, 1/2/3)\)
对踢球操作,我们将 \(A \cdot p\) 的贡献刻画到空中,将 \(B\) 刻画到踢球时刻,具体的:
- 连边 \(((x, y, 2), (x', y', 2), A)\),刻画前后飞
- 连边 \(((x, y, 3), (x', y', 3), A)\),刻画左右飞
- 连边 \(((x, y, 1), (x, y, 2/3), B)\),刻画踢球时刻
对运球操作,四连通连边即可,即 \(((x, y, 1), (x', y', 1), C)\)
对跑动 + 接球操作,考虑预处理出离 \((x, y)\) 最近的球员跑过去的贡献 \(w_{x, y}\),连边 \(((x, y, 2/3), (x, y, 1), w_{x, y})\)
预处理可以 bfs,这部分时间复杂度 \(O(nm)\)
最后跑最短路即可;总时间复杂度 \(O(nm \log nm)\)
9.16
P10652 [ROI 2017] 前往大都会 (Day 1) (最短路 DAG + 斜率优化 DP)
对第一问,直接建图最短路即可
考虑如何解决第二问
由于有 "最短路" 的大前提,考虑先建出最短路 DAG,这样就可以扔掉这个限制
考虑在最短路 DAG 上 DP;先从简单情况考虑
若最短路 DAG 为一条链,可以直接设 \(f_i\) 表示到点 \(i\) 的答案
显然,一条铁路在链上会被切成很多段,我们应该将每段看成不同的铁路考虑
转移即为 \(f_i \leftarrow f_j + (\text{dis}_i-\text{dis}_j)^2\),要求 \(i, j\) 在最短路 DAG 上属于同一铁路连续段
拆开转移式,为 \(f_i \leftarrow f_j + \text{dis}_i^2 + \text{dis}_j^2 - 2 \text{dis}_i \text{dis}_j\);这显然可以斜率优化,利用 \(2\text{dis}_i\) 单增,可以做到 \(O(n)\)
当最短路 DAG 不为一条链时,我们可以按拓扑序更新,维护每个铁路连续段的凸包
具体的,更新点 \(i\) 时,先把 \(i\) 放在每个凸包中查询得到 \(f_i\),再将 \(i\) 对应的点加入每个凸包即可
时间复杂度 \(O(s \log s + s)\)
以下是斜优复习部分
考虑将转移式变为 \(F_1(j) = F_2(i)F_3(j) + F_4(i)\) 即 \(y = kx+b\) 的形式
将 \(f_i = f_j + \text{dis}_i^2 + \text{dis}_j^2 - 2 \text{dis}_i \text{dis}_j\) 移项,可得 \(f_j + \text{dis}_j^2 = 2 \text{dis}_i \text{dis}_j + f_i - \text{dis}_i^2\)
将 \((\text{dis}_j, f_j+\text{dis}_j^2)\) 看作平面直角坐标系内一点,画出经过该点的斜率为 \(2 \text{dis}_i\) 的直线,此时 \(f_i-\text{dis}_i^2\) 即为直线的截距
我们需要最大化 \(f_i\),可视作让斜率为 \(2 \text{dis}_i\) 的直线从上向下平移,第一次碰到点时的截距即为所求
设有三点 \(A, B, C\),其中 \(x_A < x_B < x_C\);考虑什么时候 \(B\) 能被 \(A, C\) 偏序
若斜率 \(K_{AB} \le K_{BC}\),直线斜率为 \(k_0\):
- 若 \(k_0 \ge K_{AB}\),\(A\) 不劣于 \(B\)
- 若 \(k_0 \le K_{BC}\),\(C\) 不劣于 \(B\)
- 综上,\(B\) 有用当且仅当 \(K_{BC} < k_0 < K_{AB}\);但由 \(K_{AB} \le K_{BC}\),这种情况不合法
因此,必然有 \(K_{AB} > K_{BC}\);容易发现只需维护一个上凸包
考虑对于斜率 \(k_0\),如何判断在哪个点取到最大值
设上凸包中的点从左往右依次是 \(Q_1, Q_2, \cdots, Q_{\text{cnt}}\)
从右往左枚举点,设当前枚举到 \(Q_j\);若 \(k_0 \ge K_{Q_jQ_{j-1}}\),说明 \(Q_j\) 没有 \(Q_{j-1}\) 优,继续向下枚举;反之点 \(Q_j\) 必然最优
本题中,由于 \(k_0\) 单增,当前不优的点以后也不优,可以直接弹出;查询总时间复杂度就是 \(O(n)\) 的
若 \(k_0\) 没有单调性,可以在凸包上二分,查询总时间复杂度 \(O(n \log n)\)
考虑求出 \(f_i\) 后,如何将 \(i\) 对应的点加入凸包
由转移式,易知 \(i\) 对应的点为 \(P_i(\text{dis}_i, f_i+\text{dis}_i^2)\)
从右往左枚举凸包中的点,设当前枚举到 \(Q_j\);显然,若 \(K_{P_iQ_j} \ge K_{Q_jQ_{j-1}}\),需要弹出 \(Q_j\);反之直接插入 \(P_i\) 即可
总插入时间复杂度 \(O(n)\)
实现上,由于 \(\text{dis}_i\) 单增,每次只会向后加点,可以用单调栈 / vector 维护凸包
9.17
P9734 [JOISC 2021] 逃走経路 (Escape Route) (Day2) (分讨 + 最短路 + 枚举瓶颈边 + 单调栈二分)
考虑将所有路径按跨天 / 不跨天分成两部分
先考虑跨天的路径;设询问为 \((u, v, t)\)
对于这种路径,又可以分成第 \(1\) 天 / 中间若干天 / 最后 \(1\) 天三部分:
-
第 \(1\) 天,我们从 \(u\) 走到某个城市 \(p\),并留在 \(p\) 待到第二天
由于有 "断边时间" 的限制,且 \(q, n\) 极不平衡,直接对每个询问从 \(u\) 跑最短路是不可取的
考虑这条路径的不变量;由于我们要在 \(p\) 待到第二天,从 \(p\) 倒推的时间其实是确定的
具体的,考虑枚举 \(p\),对每个点求出能走到 \(p\) 的最晚出发时间,记为 \(f_{p, i}\)
这可以通过从 \(p\) 时间倒流跑最短路解决
\(n\) 很小,可以求出所有的 \(f_{i, j}\),这部分时间复杂度 \(O(n^3)\)
-
最后 \(1\) 天,我们从某个城市 \(q\) 走到 \(v\)
由于已知在 \(0\) 时刻出发,容易直接最短路解决,记为 \(g_{q, i}\)
求出所有的 \(g_{i, j}\),这部分时间复杂度 \(O(n^3)\)
-
对中间若干天,容易想到若 \(g_{i, j} \le S-1\) 则连边 \((i, j, 1)\),在新图上跑最短路即可,记为 \(d_{i, j}\)
求出所有的 \(d_{i, j}\),时间复杂度 \(O(n^3)\)
-
综上,答案即为 \(\displaystyle S-t + \min_{p, q} [f_{u, p} \ge t](d_{p, q}S+g_{q, v})\)
注意到限制只与 \(p\) 有关,每次都枚举 \(p, q\) 是不必要的
考虑枚举 \(p, v\),打包预处理 \(\displaystyle \min_q (d_{p, q}S+g_{q, v})\),记为 \(\text{tot}_{p, v}\)
则答案为 \(\displaystyle S-t + \min_p [f_{u, p} \ge t](\text{tot}_{p, v})\),时间复杂度 \(O(qn)\),可以接受
再考虑不跨天的路径
对这种路径,难点在于出发时刻不确定,到达时刻也不确定
考虑我们真正关心的只是限制最严 (最早断掉) 的那条边,即瓶颈边
考虑按照瓶颈边对路径分类,枚举瓶颈边 \((x, y, l, c)\),预处理此时 \(u, v\) 间路径的信息
本质上,此时我们已经确定了 "最晚到 \(x\) 的时刻" 以及 "从 \(y\) 出发的时刻" 两个不变量,类似之前的思路:
-
预处理 \(\text{pre}_i\) 表示从 \(i\) 出发,能在 \(c-l\) 时刻及以前到达 \(x\) 的最晚出发时间
预处理 \(\text{suf}_i\) 表示从 \(y\) 在 \(c\) 时刻出发,到 \(i\) 的最早时间
-
综上,瓶颈边为 \((x, y)\) 时,答案即为 \(\text{suf}_v-\text{pre}_u\),要求从 \(u\) 在 \(\text{pre}_u\) 时刻及以前出发
考虑对所有瓶颈边预处理,时间复杂度 \(O(n^2m)\)
考虑单调栈维护 \((u, v)\) 间的所有可选路径,按最晚出发时间升序加入,淘汰掉最晚出发时间更早 + 距离更长的路径
查询时做单调栈上二分即可,时间复杂度 \(O(q \log m)\)
综上,总时间复杂度 \(O(n^3 + n^2m + qn + q \log m)\)
9.18
P4637 [SHOI2011] 扫雷机器人 (缩点 + 有用点概率转所有点概率 - 枚举排列 + bitset 维护可达性)
若 \(u\) 能引爆 \(v\),则连边 \(u \rightarrow v\),考虑先缩点,记第 \(i\) 个 SCC 的大小为 \(\text{siz}_i\)
"在未引爆地雷中随机引爆" 很烦,因为未引爆地雷会动态变化,我们没法很好的刻画答案
考虑把 CF1773G - Game of Questions 的思路逆过来:
-
在 CF1773G 中,我们发现相邻两次 "关键问题" (能使场上存活的人变化) 间的 "无效问题" 的概率是不必考虑的
-
在本题中,考虑把相邻两次 "主动引爆的地雷" 间的 "间接引爆的地雷" 补上
具体的,每次我们在还未选择的地雷中随机选一个,若其已经被间接引爆则跳过
此时,引爆序列会形成一个排列
综上,即随机一个排列,其贡献为其中 "主动引爆的地雷" 的个数
考虑拆贡献;点 \(i\) 有贡献当且仅当在所有能主动 / 间接引爆它的点中,它在排列中第 \(1\) 个出现
设点 \(i\) 的大小为 \(\text{siz}_i\),能主动 / 间接引爆它的点的大小之和为 \(\text{cnt}_i\),则点 \(i\) 的贡献就是 \(\displaystyle \frac{\text{siz}_i}{\text{cnt}_i}\)
按拓扑序更新,bitset 维护可达性即可
时间复杂度 \(\displaystyle O(\frac{nm}{w})\)
9.19 - 9.20
复习 CSPS 初赛 + 初赛 + 摆烂
9.21
模拟赛
9.21 T1 - 巅峰对决 (数组配对 / 打表找规律)
部分分:\(O(n^3)\)
逆序对的形式启示我们从大到小填,往已经填的里插
记 \(f_{i, j, 0/1}\) 表示从大到小填到 \(i\),共填了 \(j\) 个数,逆序对个数为偶 / 奇的方案数
转移大概为 \(f_{i, j, 0/1} \leftarrow f_{i+1, j-k, 0/1} \times w(j-k, k, 0/1)\)
其中,\(w(i, j, 0/1)\) 表示已有 \(i\) 个数,将 \(j\) 个小于已有所有数的值插进去,形成偶 / 奇个新逆序对的方案数
具体的,\(w(i, j, 0/1)\) 为类似组合数卷积的形式,可以 \(O(n^3)\) 预处理
初始值为 \(f_{m+1, 0, 0} = 1\),答案为 \(f_{1, n, 0}\)
DP 转移是 \(O(n^3)\) 的,总时间复杂度 \(O(n^3)\)
正解:
看到逆序对数奇偶,考虑对数列进行两两配对
若 \(n\) 为偶数:
-
按 \((a_1, a_2), (a_3, a_4), \cdots\) 的方式对数列内部两两分组
-
若有 \(a_1 = a_2, a_3 = a_4, \cdots\),容易发现每个逆序对都会贡献偶数次,必满足要求,方案数为 \(m^\frac{n}{2}\)
-
反之,找到第 \(1\) 个满足 \(a_{2i-1} \ne a_{2i}\ (i \ge 1)\) 的 \(i\),按 \(i\) 对数列进行分类
-
容易发现,交换 \(a_{2i-1}, a_{2i}\) 后必会使逆序对数奇偶性变化
此时,令交换 \(a_{2i-1}, a_{2i}\) 形成的数列与原数列配对,必然为双射 (都能两两配上)
这种情况的方案数为 \(\displaystyle \frac{m^n-m^{\frac{n}{2}}}{2}\)
-
综上,此时总方案数为 \(\displaystyle \frac{m^n+m^{\frac{n}{2}}}{2}\)
若 \(n\) 为奇数,只需多考虑 \(a_1 = a_2, a_3 = a_4, \cdots, a_{n-2} = a_{n-1}, a_n\) 的情况
由于 \(a_n\) 在末尾,贡献也必然为偶,成立
综上,此时总方案数为 \(\displaystyle \frac{m^n+m^{\frac{n-1}{2}} \times m}{2}\)
合并两种情况,答案为 \(\displaystyle \frac{m^n+m^{\lceil \frac{n}{2} \rceil}}{2}\)
细节上,对于 \(2\) 没有逆元的情况,可以先对 \(2p\) 取模,最后再把答案除以 \(2\)
主播主播,观察性质太费脑子了,有没有简单又快速的方法?
有的,兄弟有的,打表
你说得对,但是题解确实写了 "出题人希望选手打表找出规律"
反思:
- 你说得对,但是我表都打出来了还没看出规律,那咋办
- 有时候就是会在 T1 遇到这种 adhoc,不能全场死磕 T1,应该推推其他题
9.21 T2 - 月 (贪心 - 两两配对 + 连边刻画)
部分分:\(z_i = 0\)
典题,考虑先按 \(x_i\) 排序取走第 \(1\) 个,剩下的按 \((2, 3), (3, 4), \cdots\) 两两配对,每对取 \(y_i\) 更大的
对 \(x_i\),最劣情况即取 \(x_1, x_3, x_5, \cdots\),但此时有 \(x_1 > x_2, x_3 > x_4, \cdots\),正确性没问题
对 \(y_i\),每组都取更大的,正确性显然也没问题
正解:
首先,为方便讨论,若 \(n\) 为奇数则补一个 \((0, 0, 0)\) 变成偶数
\(\lceil \frac{n}{2} \rceil+1\) 实际上多给了一次选择,而我们正好多出了一维
考虑对 \(y_i\) 按同样的方式处理,排序后取走第 \(1\) 个,剩下的配对
对 \(x_i\) 与 \(y_i\) 的所有配对,只需满足每对至少取走一个,\(x_i\) 与 \(y_i\) 的限制就符合要求
这启示我们连边刻画
具体的,将每对的两个点连边;显然每个点只会连两条边,因此形成了许多偶环
\(x_i, y_i\) 的要求转化为对每条边,我们要选择其中至少一个端点
仍然考虑配对思想,每个环有全选奇数号点 / 全选偶数号点两种方式,取 \(\sum z_i\) 更大的即可
显然,这样构造时 \(z_i\) 的限制也一定能满足
反思:
- 之前做过弱化版,不应该没想出来;还是理解不够深刻
- 还是不应该死磕 T1;相比 T1,其实这题我更可能想出来
9.21 T4 - 神秘的字符串题 (转化限制 + 括号树上树形 DP)
套路地,考虑建出括号树
关键就在于如何刻画 "向前平移"
考虑设 \(t_i\) 表示第 \(i\) 位的左括号最终在哪里被消掉
事实上,我们只需满足如下条件:
- \(t_i \le i\),因为只能向前移
- \(t_i \equiv i\ (\bmod 2)\),因为移动步长为 \(2\)
- \(t_i \ge t_{\text{fa}_i}\),因为 \(\text{fa}_i\) 相对 \(i\) 更靠前
其余的不合法情况 (如一个括号跨过另一个括号) 都可以调整成代价相等且合法的情况
考虑对 \(t_i\) DP;具体的,令 \(f_{u, i}\) 表示 \(u\) 在 \(i\) 处消掉,\(u\) 子树的最小代价
转移为 \(\displaystyle f_{u, i} \leftarrow c_i + \sum_v \min_{j \ge i} f_{v, j}\ (v \in \text{son}_u)\),且 \(i\) 对 \(u\) 合法
显然可以记录后缀 \(\min\) 优化,时间复杂度 \(O(n^2)\)
反思:刻画能取到的充要条件是个常见 trick,需要记住
9.22
9.21 T3 - 不经典矩阵题 (笛卡尔树 + 大力分讨)
考虑 "经典矩阵题"
枚举答案矩形上边界所在行 \(i\),对第 \(j\) 列,记从第 \(a_{i, j}\) 开始向下的极长 0 连续段长度为 \(h_j\)
容易发现这是最大子矩形问题,建笛卡尔树解决即可
时间复杂度 \(O(nm)\)
考虑原问题
首先解决 0 变 1 的情况
设 \(a_{i, j}\) 从 0 变 1,容易发现答案矩形只能全部在其上 / 下 / 左 / 右,即:
- 上边界最小为 \(i+1\)
- 下边界最大为 \(i-1\)
- 左边界最小为 \(j+1\)
- 右边界最大为 \(j-1\)
对四个方向分别做一次 "经典矩阵题",取前缀 / 后缀 \(\max\) 更新答案即可
这部分时间复杂度 \(O(nm)\)
再解决 1 变 0 的情况
考虑在 "经典矩阵题" 做法的基础上,再把 \(1\) 个 1 变成 0 会带来什么变化
仍然枚举答案矩形上边界 \(i\),考虑再枚举更改后的最短极长 0 连续段长度所在位置 \(j \ (1 \le j \le m)\),分讨:
-
选择更改 \(j\) 所在列的上个
1,容易得到此时新的 \(h_j\)向左右两边分别二分,得到 \(h_j\) 管辖的最宽范围即可
这部分时间复杂度 \(O(nm \log m)\)
-
选择更改限制 \(j\) 所在列取得最小值的位置 \(k\) 所在列的上个
1(即拓宽 \(h_j\) 管辖范围)此时可以选择向左改 / 向右改,要求此时新的 \(h_k \ge h_j\),两边分别维护一次即可
向 \(k\) 的更左侧 / 更右侧 + \(j\) 的右侧 / 左侧二分,求出 \(h_j\) 的新管辖范围
这部分时间复杂度 \(O(nm \log m)\)
综上,总时间复杂度 \(O(nm \log m)\)
事实上,我们只需要动态维护 \(h_j\) 左 / 右第 \(1\) 个与第 \(2\) 个满足 \(h_k < h_j\) 的位置 \(k\)
注意到随着 \(i \leftarrow i-1\),\(h_j\) 的变化只能是清零或 \(+1\)
根据这一性质,可以考虑链表维护 \(h_j\),查前驱的前驱做到 \(O(nm)\)
9.23
CF1361E - James and the Chase (随机化 + dfs 树分讨 + Tarjan 思想)
考虑如何判断一个点 \(u\) 是否是 "好点"
以点 \(u\) 为根建 dfs 树,则 \(u\) 是好点等价于不存在横叉边与前向边
这启示我们在以 \(u\) 为根的 dfs 树上考虑;接下来考虑如何判断另一点 \(v\) 是否是好点
由于有 "简单路径" 的限制,\(v\) 到其子树中的点必然满足要求
对 \(v\) 子树外的点:
-
由于强连通的性质,每个点必然被至少 \(1\) 条返祖边覆盖
P.S. 此处称返祖边 \((x, y)\) 覆盖点 \(v\),当且仅当 \(x\) 在 \(v\) 子树中且 \(y\) 是 \(v\) 的祖先
-
若 \(v\) 子树中有 \(\ge 2\) 条返祖边覆盖了 \(v\),则 \(v \rightarrow \text{fa}_v\) 有 \(\ge 2\) 条简单路径,\(v\) 不为好点
-
若 \(v\) 子树中只有 \(1\) 条返祖边覆盖 \(v\),设为 \((x, y)\):
-
若 \(y\) 为好点,\(v\) 也为好点,因为从 \(v\) 到 \(v\) 子树外的点必须先经过 \(y\)
-
若 \(y\) 不为好点,显然覆盖 \(y\) 的返祖边的端点不能在 \(v\) 子树中 (不然 \(v\) 就会被两条返祖边覆盖)
设 \(y \rightarrow z\) 有两条简单路径,\(v \rightarrow y \rightarrow z\) 同样会有两条,\(v\) 不为好点
-
综上,点 \(v\) 为好点,当且仅当满足:
- \(v\) 被恰好 \(1\) 条返祖边覆盖
- 覆盖 \(v\) 的返祖边 \((x, y)\) 满足 \(y\) 是好点
对限制 \(1\),可以树形 DP 解决
令 \(f_u\) 表示 \(u\) 被多少条返祖边覆盖,\(\text{in}_u\) 表示有多少条返祖边指向 \(u\),\(\text{out}_u\) 表示有多少条返祖边从 \(u\) 引出
转移为 \(f_u \leftarrow \text{out}_u - \text{in}_u + \sum f_v\ (v \in \text{son}_u)\)
初始值为对叶子 \(u\),有 \(f_u = \text{out}_u\)
对限制 \(2\),考虑 Tarjan 思想,\(\text{low}\) 数组即为所求
现在回过头考虑如何求出一个好点
注意到 "好点个数 \(\le 0.2n\) 则输出无解" 的限制,考虑随机化
随机 \(50\) 次,每次暴力建树 check 即可
时间复杂度 \(O(n+m)\),\(50\) 倍常数
P3209 - 平面图判定 (刻画限制 + 观察上界 + 2-SAT)
考虑 "保证存在哈密顿回路" 这个性质的作用
考虑将哈密顿回路画在平面上,必然将整个平面分成了两部分;其余的边要么连在环里,要么连在环外
设点 \(u\) 在回路上的编号为 \(\text{id}_u\);则边 \((u_1, v_1), (u_2, v_2)\) 冲突当且仅当 \([\text{id}_{u_1}, \text{id}_{v_1}], [\text{id}_{u_2}, \text{id}_{v_2}]\) 相交且两边均连在环内 / 外
对每条非回路边建两个点表示在环内 / 环外,2-SAT 刻画冲突关系即可
直接做时间复杂度 \(O(m^2)\),需要优化
显然,环内最多连 \(n\) 条边,环外同理;那么总共最多连 \(n+n+n = 3n\) 条边 (还要加上环上边)
因此,\(m > 3n\) 时直接输出无解,反之 2-SAT 即可
时间复杂度 \(O(n^2)\)
以下为 2-SAT 复习部分
设限制为 "\(x_i\) 为真则 \(y_i\) 为假",连边 \((x_i, 1) \rightarrow (y_i, 0)\) 与其逆否命题 \((y_i, 1) \rightarrow (x_i, 0)\),表示 \(u\) 能推出 \(v\)
对每个 SCC,其中一个点成立则其他的点都成立;因此考虑缩 SCC
设点 \(i\) 所在编号为 \(\text{scc}_i\);显然,若存在 \(u\) 使得 \(\text{scc}_{(u, 1)} = \text{scc}_{(u, 0)}\),则矛盾,必然无解
反之,构造时 \(u\) 取 \(\text{scc}_{(u, 0)}\) 与 \(\text{scc}_{(u, 1)}\) 中拓扑序更大的点对应的布尔值即可
实现上,SCC 编号越大代表越晚出栈,越晚出栈则拓扑序越小,直接取 SCC 编号较小的点作为答案即可
时间复杂度 \(O(n)\)
ABC277Ex - Constrained Sums (2-SAT - 对值域拆点刻画赋值)
注意到值域 \(m\) 很小,考虑对值域拆点
具体的,把每个变量拆成 \(2(m+2)\) 个点,分别表示 \([x _i \ge j], \neg [x_i \ge j]\ (j \in [0, m+1])\)
首先考虑每个变量拆出的点间的限制:
-
\(x_i \ge 0\) 必然成立,连边 \(\neg [x_i \ge 0] \rightarrow [x_i \ge 0]\)
-
\(x_i \ge m+1\) 必然不成立,连边 \([x_i \ge m+1] \rightarrow \neg [x_i \ge m+1]\)
-
\(x_i \ge j+1\) 则 \(x_i \ge j\),连边 \([x_i \ge j+1] \rightarrow [x_i \ge j]\)
同时,对其逆否命题连边 \(\neg [x_i \ge j] \rightarrow \neg [x_i \ge j+1]\)
再考虑题目的限制 \(L_i \le x_{a_i}+x_{b_i} \le R_i\):
-
显然,\(x_{a_i}, x_{b_i} \le R\),连边 \([x_{a_i} \ge R_i+1] \rightarrow \neg [x_{a_i} \ge R_i+1]\),对 \(x_{b_i}\) 同理
-
显然,\(x_{a_i}, x_{b_i} \ge L_i-m\),连边 \(\neg [x_{a_i} \ge L_i-m] \rightarrow [x_{a_i} \ge L_i-m]\),对 \(x_{b_i}\) 同理
-
\(x_{a_i} \ge j\) 则 \(x_{b_i} < R_i-j+1\),连边 \([x_{a_i} \ge j] \rightarrow \neg [x_{b_i} \ge R_i-j+1]\)
对称的,连边 \([x_{b_i} \ge j] \rightarrow \neg [x_{a_i} \ge R_i-j+1]\)
-
\(x_{a_i} < j\) 则 \(x_{b_i} \ge L_i-j+1\),连边 \(\neg [x_{a_i} \ge j] \rightarrow [x_{b_i} \ge L_i-j+1]\)
对称的,连边 \(\neg [x_{b_i} \ge j] \rightarrow [x_{a_i} \ge L_i-j+1]\)
-
P.S. 以上要求出现的数都 \(\in [0, m+1]\),否则不连该边
跑 2-SAT 并构造方案即可
时间复杂度 \(O(nm)\)
9.24
打罕见的阳间场 CodeForces Round 1053 (Div.2)
咋回事,D 都切不了,还是太不会观察性质了……
CF2151A - Incremental Subarray (观察性质)
CF2151B - Incremental Path (模拟)
CF2151C - Incremental Stay (观察性质 - 向中心移动,隔位前缀和)
9.25
P5332 [JSOI2019] 精准预测 (2-SAT + 观察图性质 + 分组 bitset)
显然,一个火星人若在 \(t+1\) 时刻活,\(t\) 时刻必然活;\(t\) 时刻若死,\(t+1\) 时刻也必然死
注意到这与 \([x_i \ge j]\) 类似,考虑 ABC277Ex - Constrained Sums 的套路,对每个火星人拆点刻画生存状态
记 \((i, j)\) 表示第 \(i\) 个火星人在 \(j\) 时刻活,\(\neg (i, j)\) 表示死
类似的,连边:
- \((i, j+1) \rightarrow (i, j)\)
- \(\neg (i, j) \rightarrow \neg (i, j+1)\)
- 对限制 \((0, t, x, y)\),连边 \(\neg(x, t) \rightarrow \neg(y, t+1)\),及其逆反条件 \((y, t+1) \rightarrow (x, t)\)
- 对限制 \((1, t, x, y)\),连边 \((x, t) \rightarrow \neg (y, t)\),及其逆反条件 \((y, t) \rightarrow \neg (x, t)\)
但 \(O(nT)\) 个点显然无法接受
注意到只有题目输入的时间及 \(T+1\) 有用,只保留这些点,这样点数就是 \(O(n+m)\) 级别的
注意到这个图有非常好的性质:
- 生点只按 \(t\) 从大向小连边
- 死点只按 \(t\) 从小向大连边
- 生死点间只有对应 \(t\) 间连边,且总是从生点连向死点
综上,不难发现整个图是个 DAG,因此无需缩点
考虑如何求 \(\displaystyle \sum_{1 \le i \le n, i \ne k} \text{Live}(k, i)\):
-
若 \(k\) 必死 (即 \((k, T+1)\) 可达 \(\neg (k, T+1)\) ),答案为 \(0\)
-
反之,从 \((k, T+1)\) 出发遍历整张图,记到达的 \(\neg (i, T+1)\) 个数为 \(\text{cnt}\),答案为 \(n-\text{cnt}-1\) (还要除去自己)
特殊地,对必死点 \(p\),其他 \((k, T+1)\) 都必定要到达它对应的 \(\neg (p, T+1)\),这样才能保证正确性
因此,我们先求出所有必死点 \(p_i\),再建虚点 \(0\),连边 \((k, T+1) \rightarrow 0\) 与 \(0 \rightarrow p_i\)
暴力搜时间复杂度 \(O(n(n+m))\),无法接受
注意到这是 DAG 连通性问题,考虑用 bitset 维护,时间复杂度 \(O(\frac{n(n+m)}{w})\)
但这样空间会炸,这就需要用到分组 bitset 的 trick
考虑将所有 \(\neg (i, T+1)\) 每 \(B\) 个分成一组,对每组分别搜一次,只维护到组内点的可达性,最终将结果累加
一共跑 \(\frac{n}{B}\) 次,每次时间复杂度 \(O(n + \frac{B(n+m)}{w})\),空间复杂度 \(O(\frac{B(n+m)}{w})\)
综上,总时间复杂度 \(O(\frac{n^2}{B} + \frac{n(n+m)}{w})\),空间复杂度 \(O(\frac{B(n+m)}{w})\)
实现上很卡常,取 \(B = 10^4\) 时效率较高
9.26
CF2151D - Grid Counting (观察性质)
限制 \(2\) 等价于:
- 格子 \((1, 1)\) 需染黑
- 格子 \((2, 1), (2, 2), (1, 2)\) 需恰选 \(1\) 个染黑
- 格子 \((3, 1), (3, 2), (3, 3), (2, 3), (1, 3)\) 需恰选 \(1\) 个染黑
- ……
限制 \(3\) 等价于:
- 格子 \((1, n)\) 需染黑
- 格子 \((1, n-1), (2, n-1), (2, n)\) 需恰选 \(1\) 个染黑
- 格子 \((1, n-2), (2, n-2), (3, n-2), (3, n-1), (3, n)\) 需恰选 \(1\) 个染黑
- ……
由上,可发现一些格子必定不能填:
-
由限制 \(2\) 第 \(1\) 条,格子 \((1, 1)\) 需染黑
由限制 \(3\) 第 \(n\) 条,格子 \((2, 1), (3, 1), \cdots, (n, 1), (n, 2), \cdots, (n, n)\) 必不能填
对称的,格子 \((2, n), (3, n), \cdots, (n, n), (n, n-1), \cdots, (n, 1)\) 必不能填
-
由限制 \(2\) 第 \(2\) 条,格子 \((1, 2), (2, 2)\) 需恰选 \(1\) 个染黑
由限制 \(3\) 第 \(n-1\) 条,格子 \((3, 2), (4, 2), \cdots, (n-1, 2), (n-1, 3), \cdots, (n-1, n-1)\) 必不能填
对称的,格子 \((3, n-1), (4, n-1), \cdots, (n-1, n-1), (n-1, n-2), \cdots, (n-1, 1)\) 必不能填
-
……
综上,能填的区域为从左上角到右下角的斜线 + 从右上角到左下角的斜线 + 矩形上端围成的区域 (边框上也能填)
同时,我们要求每列恰好填 \(1\) 个
显然,考虑从限制严到限制松填,即从下往上填;总方案数只需乘组合数即可
时间复杂度 \(O(n \log \text{mod})\)
9.27
摆烂 + 补 whk
9.28
CF2151E - Limited Edition Shop (刻画限制 + 线段树优化 DP)
考虑按照 \(a_i\) 的顺序考虑,每个物品有被 Alice 选与被 Bob 选两种决策
我们肯定希望从前到后 DP,考虑一段 \(a_i\) 前缀的选择分配方案什么时候是合法的:
-
若指定当前分配给 Bob,则没有要求
这是因为,我们并不要求 Bob 已选的物品形成 \(b_i\) 中的前缀,实际顺序上可以视为先选在 \(a_i\) 中靠后的,再选靠前的
-
若指定当前分配给 Alice,记 Bob 已选的物品在 \(b_i\) 中的最大编号为 \(\text{id}\),当前物品在 \(b_i\) 中的编号为 \(\text{id}'\)
显然,我们要求 \(\text{id}' > \text{id}\)
容易发现,保证这一点就能使方案合法
考虑 DP;记 \(f_{i, j}\) 表示分配完 \(a_i\),\(\text{id} = j\) 时的答案
转移为:
-
将 \(a_i\) 分配给 Alice,此时要求 \(\text{id}' > j\)
有转移 \(f_{i, j} \leftarrow f_{i-1, j}+v_{a_i}\ [j < \text{id}']\)
-
将 \(a_i\) 分配给 Bob,且 \(\text{id}'\) 不为新的 \(\text{id}\)
有转移 \(f_{i, j} \leftarrow f_{i-1, j}\ [\text{id}' < j]\)
-
将 \(a_i\) 分配给 Bob,且 \(\text{id}'\) 为新的 \(\text{id}\)
有转移 \(f_{i, \text{id}'} \leftarrow f_{i-1, k}\ [k < \text{id}']\)
直接做时间复杂度 \(O(n^2)\)
这显然是线段树优化的形式,可以做到 \(O(n \log n)\)
9.29
CF1691C - Sum of Substrings (观察性质)
CF1310C - Au Pont Rouge (SA + 二分转判定 + DP check)
由于 \(n \le 1000\),可以将所有子串拿出来排序,求出 \(\text{rk}_{l, r}\)
实现上可以用 SA 维护,时间复杂度 \(O(n^2)\)
考虑二分答案串 \(s\),DP 求出有多少方案满足字典序最小的串 \(\ge s\);最后 check 是否 \(\ge k\) 即可
考虑枚举划分的子串以转移;由于确定 \(l\) 时容易比较字典序,考虑从后向前 DP
令 \(f_{i, j}\) 表示划分完 \([i, n]\),分成 \(j\) 个子串,字典序最小串 \(\ge s\) 的方案数
转移即为 \(f_{i, j} \leftarrow f_{k, j-1} [\text{rk}_{i, k+1} \ge \text{rk}_s]\);初值为 \(f_{n+1, 0} = 1\),答案为 \(f_{1, m}\)
注意到合法的 \(k\) 必然是一段后缀,可以预处理 + 后缀和优化,时间复杂度 \(O(n^2)\)
总时间复杂度 \(O(n^2 \log n)\)
CF616F - Expensive Strings (SA + 前缀和)
套路的将所有串用特殊字符隔开,建 SA 维护子串出现次数
枚举 \(i\),考虑 \(\text{h}_i\) 所在极长连续段 \([l, r]\) (满足 \(\displaystyle \text{h}_i = \min_{l \le k \le r} \text{h}_k\) ) 对应的所有原串位置:
- \([l, i]\) 对应原串中 \(\text{lcp}(\text{suf}_j, \text{suf}_i)\ [l-1 \le \text{rk}_j \le i-1]\)
- \([i+1, r]\) 对应原串中 \(\text{lcp}(\text{suf}_i, \text{suf}_j)\ [i+1 \le \text{rk}_j \le r]\)
- 当起始位置相同时,对应 \(\text{rk}_j = i\)
- 综上,需满足 \(l-1 \le \text{rk}_j \le r\)
记 \(\text{from}_i\) 表示原串位置 \(i\) 所属输入串编号;对于原串位置 \(j\),其贡献为 \(\text{h}_i \cdot \text{c}_{\text{from}_j}\)
综上,\(\text{h}_i\) 所在极长连续段 \([l, r]\) 对应的总贡献为 \(\text{h}_i \sum_{j=l-1}^{r} \text{c}_{\text{from}_{\text{sa}_j}}\)
前缀和维护即可;这部分时间复杂度 \(O(n \log n)\)
有个细节:仅考虑 \(\text{h}_i\) 无法覆盖串只出现 \(1\) 次的情况
容易发现,这种情况下仅有可能是整串
枚举串编号 \(i\),若相邻 \(\text{rk}\) 对应的前后 \(\text{lcp}\) 都 \(\ge |s_i|\),则用 \(|s_i| \cdot c_i\) 更新答案
总时间复杂度 \(O(n \log n)\)

浙公网安备 33010602011771号