刷题杂记 Pt.5
省选前刷题(?)
-
CDQ 套 CDQ 解决四维偏序。
当数点有重时如何避免重复计数:使用
stable_sort。 -
不小心重新发明了一遍斯坦纳树斯坦纳树:以 \(O(3^k + 2^k * m \log m)\) 的复杂度解决多关键点生成树问题。具体来说,设 \(f[i][S]\) 表示建立一棵以 \(i\) 为根,并连通了 \(S\) 中关键点的最小代价,并用 Dijkstra 优化 DP 转移。
Dijkstra 优化 DP 转移:当每个点有初值,且这些状态之间能够建出图来时,最优的策略并不是通过预处理出全源最短路进行转移,而是在设 \(dis\) 初值为那些初值的基础上做 DP 转移。
-
其实是比较简单的费用流问题。需要注意的是,我们既可以求“最大费用最大流”,也可以求“最小费用最大流”。
我鸽了好些题,就先不补了(
2025.2.7
省选联考 2023 Day1。
说一下大体的情况:做得比较烂。
由于寒假的逆天生物钟还没有倒过来,整场十分困倦,还睡了半小时。T1 竟然都做了 1.5h……后面的题就保龄了。
怎么改进?早睡早起身体好。
-
简单贪心题。我也不知道为什么我做了那么久。
-
一道 corner case 很多的树形 DP(可能)。
容易发现 \(k=0\) 可以通过枚举因数做到 \(O(nd(n))\),\(k=1\) 可以通过整除分块做到 \(O(n\sqrt{n})\)。重要的是接下来的部分。
核心结论:所选的边集一定连通;一个点双要么全选,要么全部不选。
然后,我们就可以在圆方树上做一个关于连通块的经典 DP:设 \(f[x]\) 表示 \(x\) 为连通块中深度最浅点的方案数,统计所有的连通块就只用枚举每个 \(f[x]\) 即可。当然这里需要浅浅修改一下,设 \(f[x]\) 表示该方点能被删掉/圆点的父亲方点能被删掉。然后“随便”讨论一下就可以了。。。
还有一种简化的方法——可以证明选择的边集连通块一定会过重心。于是就不用在最后统计答案时枚举连通块的最浅点了。
讲讲我做的时候的一些教训。我不知道为什么就是没有想到 DP——好像是因为我觉得这个题的子状态并不明显,可以直接计算。然后我不是从边集形成的连通块来考虑的,而是从删掉边集后的那些连通块来考虑的,这样也会致使做法变麻烦,因为这些连通块的形态比较复杂会让 corner case 增多。
-
咕咕。
2025.2.8
省选联考 2023 Day2
华丽地爆零了。。。
主要问题就在这个过河卒上面。
-
其实我觉得这题的代码实现没有传说的那么复杂吧。。。我反而觉得恶心的地方在思路容易伪。
显然如果没有平局就可以直接记忆化搜索做。然后我就掉到记忆化搜索的坑里面出不来了——一直试着直接把平局套进去。
正确做法是怎么做的?
首先,我们可以发现“步数”这个东西看上去很棘手。因为它似乎要求我们必须在求出每一个后继的情况下才能得出,而本题有“环”,这是很难做到的。所以,我们干脆先将它抛开,考虑简化版的问题——判断每个局面的输赢状态。于是,我们对必胜局面就有了更宽松的判断条件,其后继中只要有一个是必败即可。必胜和必败确定后,剩下的就一定是和棋。
然后考虑记忆化搜索为什么有问题。很明显,由于环的存在,我们的访问顺序可能出现错乱。这个时候以一种类似拓扑排序的方法倒着推,我们就可以确定顺序了。
那现在我们求得了每个局面的状态以后,又该怎么推步数呢?对于必败局面,这很简单——因为我们有其所有后继的信息。对于必胜局面,这就比较麻烦,因为它与其后继之间是可能形成环的。
这个时候,需要用到一个十分巧妙的 Trick——我们使用类似 BFS 的方法来实现这个拓扑排序,即使用队列来储存节点,此时它也就拥有了 BFS 的最短路特性。那么,第一个更新这个必胜局面的后继,一定满足它是最短路,我们也就可以保证该必胜局面的步数最优。
总结:
-
先思考简化版本。
-
要看到方法出错的核心问题是什么,对症下药,而不是瞎改(比如我就写了很多改版的记忆化搜索……)。
-
Trick:在一些顺序无所谓的算法中,我们可能可以通过对其顺序适当的修改,使其能够解决贪心问题。(比如之前好像还做过一道优先队列 + 拓扑排序的,还有点权排序 + 线性基。)
-
-
考试时没看这道题。感觉是一道思维难度不高,而对码力颇有挑战的题目。
概括一下就是建模为图后,只有树/基环树有解。然后讨论一下,并做树形 DP。
-
咕咕咕。
2025.2.9
省选联考 2024 Day1。
考得稀烂,再次爆零。
-
考试四个半小时拼尽全力无法战胜。
先讲思路,其实还是比较巧妙的。主要有如下两点性质:
-
在 \(m\) 固定的情况下,\(\forall x_i', y_i'\),一定取平均值最优。
这本质上可以看作针对 \(\min / \max\) 限制的一种 Trick,即若限制要使得最大值最小 / 最小值最大,取平均值就是一种不错的贪心。
-
对 \(m \bmod n\) 的不同同余系分别求最值,再求出它们中的最值。(其实这个在写出不等式以后很容易想到。)
代码有两种主要的实现方法:二分,或者直接解不等式。但其实都挺复杂的,后者应该还要相对简单一点。
我认为我之所以调试这么久,是因为我并没有保证我解不等式的函数的正确性。应该自己先手写几个不等式拿它试一下才对。【手模保证模块化函数的正确性】
-
-
还不错的一道“Trie + 分治”,不过个人感觉没有黑。。。
首先本题显然是可以二分答案的,于是转化为判定答案是否可以 \(\le kth\)。
然而情形依旧十分复杂。我们考虑简化一下——考虑如果此时 \(S\) 已经固定,我们如何求解是否存在合法的 \(x\)。首先,对于所有 \(i \in S\),检测 \(\sum b_i \le m\) 是否成立,并且求出 \(x\) 的下界 \(\max kth-a_i\)。对于 \(i \in U \backslash S\),情况则稍显复杂。这种涉及异或二进制数的比较大小问题,使用 01-Trie 来组织 \(i \in U \backslash S\) 的 \(a_i\) 是很合适的。逐位确定 \(x\) 的取值,容易发现它填 \(0/1\) 的两种情况,都只会分别向 Trie 树左右儿子中的一个递归继续搜索,那么全树的点都只会遍历一次,故我们可以在 \(O(nk)\) 的复杂度内完成判定。
现在考虑 \(S\) 同样也不确定时我们应该如何判定。依然考虑在 01-Trie 的结构上递归来进行判定。对于一个点,我们现在有三种决策:放入 \(S\)、\(x\) 填 \(1\)、\(x\) 填 \(0\)。显然,放入 \(S\) 的决策我们用得越少越好。所以,只有当 \(kth\) 该位为 \(1\) 时,在左右儿子中选择一个加入 \(S\),并将 \(x\) 该位填为 \(0\);否则,选择 \(x\) 填 \(0/1\)。
不过现在的复杂度是 \(O(nk^2)\) 的,还不足以通过,我们需要一个 \(O(nk)\) 的算法。01-Trie 上分治的过程极难优化掉,考虑将二分的过程与分治结合。递归到某个节点时,我们需要 \(O(1)\) 判定能否做到在 \(kth\) 该位填 \(1\)、后面位填 \(0\) 的情况下有解。根据上面的结论,有一个性质,即 \(x\) 的后面位可以贪心地全部填 \(1\)。于是只用简单判断一下 \(\sum b_i\) 和 \(x\) 是否在限制内即可。【这个优化的本质是什么?我想是由于分治是逐位推进的,而二分实质也是逐位确定是否填 \(1\) 的。线段树二分、树状数组上倍增也是同样的原理。】
-
咕咕咕。
2025.2.11
省选联考 2024 Day2。
感觉发挥得还可以,因为 T1 刚好在我的舒适区内。
-
简单提几个点:
-
字典序最大/小化的题目,不用说,都是判定使得第一个数尽量大是否合法即可。
-
这道题的关键我觉得在于看出来它需要 DP 预处理,以及这个 DP 要这么去设状态。而这必须结合实际情况考量。我认为支撑我们想到 DP 的一个方法是——“这个限制很棘手,我们就干脆把它放到 DP 状态内去。”
-
然后就是优化部分。题解给出的优化是归并 DP 数组。我没有想到,而是采用了对于树形 DP 的一种更普遍的方法——线段树合并。(由于本题的特殊性,这里使用的还是可持久化的线段树合并。)
-
线性规划
-
线性规划是什么?
用人话来讲,就是给定若干变量,它们满足一些线性不等式或等式的限制,要求最大化或最小化一个关于这些变量的线性函数。
形式化地,我们可以用矩阵的形式表示一个线性规划。其中 \(x\) 为一 \(1 \times n\) 未知向量,\(c\) 为代表目标函数的 \(1 \times n\) 向量,\(b\) 为一代表限制的 \(1 \times m\) 向量,\(A\) 则为一代表限制的 \(n \times m\) 矩阵:
\[\max f(x) = c^Tx \]\[s.t \begin{cases} Ax \le b \\ x \ge 0 \end{cases} \]上面的形式被称为线性规划的 标准型。显然,任何线性规划都可以通过转化得到该形式。
然而,有时候我们为了方便,会将它化为另外一种形式:
\[\max f(x) = c^Tx \]\[s.t \begin{cases} Ax = b \\ x \ge 0 \end{cases} \]上面的形式被称为线性规划的 松弛型。显然,任何线性规划也都可以通过转化得到该形式。
-
如何将一个线性规划问题转化为松弛型?
如果你想将问题转化为标准型的,实际是类似的。
-
如果目标函数是 \(\min\),则整体全部取反,转化为 \(\max\)。
-
如果约束为不等式,可以通过引入一些非负变量(又称松弛变量)来转化为等式。
-
如果存在取值无约束的变量,可转化为两个松弛变量的差。
-
-
可以表示为线性规划的题目有哪些?
虽然说线性规划的一般解决方法是单纯形法,但针对其中的一些特殊模型,我们有更优的时间复杂度解法。如果能将问题转化为与它们类似的形式,我们就可以试着用这些更优的解法解决。
-
最短路
\[\max d[t] \]\[s.t \begin{cases} d[v] \le d[u] + w(u,v) & \forall (u, v) \in E \\ d[s] = 0 \end{cases} \] -
最大流
\(s, t\) 分别为源点、汇点。
\[\max \sum_{(s, v) \in E} f(s, v) \]\[s.t \begin{cases} 0 \le f(u, v) \le c(u, v) & \forall (u, v) \in E \\ \sum_{(v, u) \in E} f(v, u) = \sum_{(u, v) \in E} f(u, v) & \forall u \in V, u \ne s,t \\ \sum_{(s, v) \in E} f(s, v) = \sum_{(v, t) \in E} f(v, t) \end{cases} \] -
恒定流量最小费用流
\(k\) 为一常数,代表恒定流量。
\[\max \sum_{(u, v) \in E} f(u, v) w(u, v) \]\[s.t \begin{cases} 0 \le f(u, v) \le c(u, v) & \forall (u, v) \in E \\ \sum_{(v, u) \in E} f(v, u) = \sum_{(u, v) \in E} f(u, v) & \forall u \in V, u \ne s,t \\ \sum_{(s, v) \in E} f(s, v) = \sum_{(v, t) \in E} f(v, t) = k \end{cases} \] -
多商品流
据说该问题的唯一已知多项式解法就是线性规划。
用人话描述一下这个问题:有 \(k\) 种不同的商品,分别要从 \(s_i\) 流往 \(t_i\),且流量须恰好为 \(d_i\)。对于每条边,所有商品所消耗的容量和不能超过 \(c(u, v)\),且每条边单位流量的费用为 \(w(u, v)\)。问在满足每个商品的条件的情况下的最小总费用是多少。
形式化就略了,毕竟和上面大同小异。
-
-
全幺模矩阵
定义:如果矩阵的所有子方阵的行列式都是 \(0\) 或 \(\pm 1\),那么矩阵就称为一个全幺模矩阵。
性质 1:全幺模矩阵中的元素一定都为 \(0\) 或 \(\pm 1\)。但需要注意的是,该性质的逆命题并不成立。
性质 2:如果一个线性规划的约束矩阵为全幺模矩阵,那么约束变量的解一定都为整数。
可以证明,上面举的那几个例子的约束矩阵都为全幺模矩阵。
-
对偶原理
对于任意一个线性规划问题的标准型形式,都存在一个与之对应的问题,满足为原始问题的最大化与最小化互换、常数与目标函数互换、不等号变向、约束矩阵转置,且最终答案相等。
形式化地,对于以下两个线性规划:
\[\max f(x) = c^Tx \]\[s.t \begin{cases} Ax \le b \\ x \ge 0 \end{cases} \]\[\min g(y) = b^Ty \]\[s.t \begin{cases} A^Ty \ge c \\ y \ge 0 \end{cases} \]满足 \(\max f(x) = \min g(y)\)。
具体证明见《算法导论》29.4。
一些对偶问题的举例:
-
任意图中,最大独立集 = 最小点覆盖
最大独立集:
\[\max \sum_{u \in V} x_u \]\[s.t \begin{cases} x_u + x_v \le 1 & \forall (u, v) \in E \\ 0 \le x_u \le 1 & \forall u \in V \end{cases} \]最小点覆盖:
\[\min \sum_{(u, v) \in E} y_{uv} \]\[s.t \begin{cases} \sum_{(u, v) \in E} y_{uv} \ge 1 & \forall u \in V \\ 0 \le y_{uv} \le 1 & \forall (u, v) \in E \end{cases} \] -
最大流最小割定理:证明见 该知乎回答。其实就看下他列出的约束矩阵即可。
-
Konig 定理
内容即二分图最大匹配 = 二分图最小点覆盖。
容易发现每组匹配都对应一个流,每组点覆盖都对应一组割。故正确性同最大流最小割定理。
-
Dilworth 定理 & Mirsky 定理
首先,对于一个 DAG,我们有如下定义:
-
链:DAG 上的路径。
-
反链:一个点集,满足其中任意两个点都不在同一条链上。
-
最小链点覆盖:最小化选择的链数量,使得选择的链能够覆盖 DAG 上所有点至少一次。
有引理:
-
Dilworth 定理:最长反链长度 = 最小链点覆盖
-
Mirsky 定理:最长链长度 = 最小反链点覆盖
这里以 Dilworth 定理举例,Mirsky 定理应该是大同小异的。
设 \(\mathcal{P}\) 为 DAG 上所有链的集合,\(P \in \mathcal{P}\) 表示一条链。
最长反链长度:
\[\max \sum_{u \in V} x_u \]\[s.t \begin{cases} \sum_{u \in P} \le 1 & \forall P \in \mathcal{P} \\ x_u \ge 0 & \forall u \in V \end{cases} \]最小链点覆盖:
\[\min \sum_{P \in \mathcal{P}} y_{P} \]\[s.t \begin{cases} \sum_{u \in P} y_P \ge 1 & \forall u \in V \\ y_P \ge 0 & \forall P \in \mathcal{P} \end{cases} \]fun fact:我刚刚在研究这个问题的时候,得到了一个错误的做法——由于最小链点覆盖有一个经典的 Floyd 跑传递闭包再二分图拆点做法,我就试着用传递闭包得到的新边集 \(E'\) 来表示这两个线性规划。然后在第一个问题中,我就写出了一个形如 \(x_u + x_v \le 1, \forall (u, v) \in E'\) 的限制,乍一看很对,但实际不然——因为 \(x_u\) 在这里不一定是在整数时取得最优解!这里就是上面说的,约束矩阵所有元素都为 \(0, \pm 1\),但是并不为全幺模矩阵的情况。
-
-
Hall 定理(?)

-
最小割和对偶图最短路
-
-
单纯形法
单纯形法是最简单的求解一般线性规划的方法。它的效率一般情况下还可以接受,通过 \(n = 100\) 的规模没有问题,然而理论上可能被卡到 \(O(2^n)\)。当然,线性规划存在多项式解法,但在这里不予探讨。
我还没研究怎么写,先咕了。。。

浙公网安备 33010602011771号