唐山一中2026暑假集训 I
Day 1
LCA与树上差分
LCA很简单,这里不再赘述。
- P1600 [NOIP 2016 提高组] 天天爱跑步。
一道经典题,虽然创飞了很多人。
我们首先进行一些转化:考虑对于每一个观察员 \(u\),并且 \((s, t)\) 是一段路程,最近公共祖先记为 \(LCA\)。
先考虑对于 \(u\) 在 \((s, LCA)\) 上的情况,则定有 \(dep_s - dep_u = w_u\),移项可得 \(dep_s = dep_u + w_u\)。
我们假设存在两个 vector,一个叫做 vector1,另一个叫做 vector2。第一个表示有哪些元素在这个位置加上,第二个表示有哪些元素需要在这里删掉。形式化的。也就是 vector1 在 \(s\) 对应的位置加入一个 \(dep_s\),同时在 vector2 在 \(LCA\) 对应的位置加入一个 \(dep_s\)。
我们再设一个桶的数组叫做 \(a\)。当我们从 vector1 中每一个 \(x\) 在 \(a\) 上加上 \(1\);在 vector2 中的每一个 \(x\) 在 \(a\) 中减掉 \(1\)。但是,我们考虑一个问题,因为修改是对于子树存在影响的,所以我们很容易知道其实对于观察点 \(u\) 产生的影响其实是 \(\Delta a_{dep_u + w_u}\)。
同理,我们可以非常轻松知道如果 \(u\) 位于 \((t_i, LCA)\) 上时我们可以通过同样的方法求解。
复杂度O(能过)。
MST
最小生成树大家都会,那就来一点不一样的。
最小生成树很简单,这里就简单介绍一下性质:
- 最小生成树树边上 \(u, v\) 满足 \(u\) 到 \(v\) 上的路径最大值最小。
- Boruvka 算法
再介绍一下第三种求最小生成树做法: Boruvka 算法。
\(1.\) 我们将每个点视为孤独集合
\(2.\) 重复以下过程:
- 找到每个集合向外连边的最小值;
- 对于这些边进行去重;
- 合并剩下两条边连接的两个点。
注意到每次至少合并任意 \(2\) 个集合,所以执行次数最多是 \(O(\log n)\),所以我们可以使用一些暴力的方法计算。
- P4180 [BJWC2010] 严格次小生成树。
首先,我们发现严格次小生成树一定是在最小生成树上替换掉一条边所产生的。所以,首先我们直接就枚举每一条边 \((u, v)\),然后考虑对于这条边可以进行怎样的操作。
注意到我们一定是 \(u, v\) 上的路径的 \(len < w(u, v)\) 的 \(len\) 的最大值。然后我们发现这个可以通过树上倍增求出,然后就可以了。
Day 2
-
P4001 [ICPC 2006 Beijing R] 狼抓兔子。
注意到答案就是原图的最小割。
考虑一个叫做对偶图的东西,对于对偶图,我们考虑对于每一个 \(u\)(将每一个对偶图视为点)和所有相邻的对偶图连起来。然后,我们考虑对于所有在边上的对偶图,分别和初始源点和最终汇点连接起来,最短路径即为原图最小割。
证明略。(其实是我不会)。 -
CF1753D The Beach。
难度在于建图。
我们会注意到一些关键细节。
考虑对于图进行黑白染色。对于所有 \(i + j\) 是奇数的点我们记为黑色,对于所有 \(i + j\) 是偶数的点我们记为白色。
然后,我们注意到对于空格的点,无论是旋转还是平移,最终一定会移到和这个点颜色相同的点。所以,我们考虑把一个床相邻的空格点连起来,然后分别对于黑色和白色跑最短路径,所以最后我们直接枚举所有的点对然后求出答案即可。 -
CF2178H Create or Duplicate。
很牛的一道题。
首先,我们考虑对于最后的翻倍操作。加入我们每一次都会把所有的物品都进行翻倍。那么,我们很容易得到一个同余最短路的做法:(以下全部假设在模 \(m\) 意义下)
-
\(i\) 向 \(i + a\) 连一条边权为 \(a\);
-
\(i\) 向 \(i + b\) 连一条边权为 \(b\);
-
\(i\) 向 \(i + c\) 连一条边权为 \(c\);
-
\(i\) 向 \(2 \times i\) 连一条边权为 \(k\);
然后,我们充分发扬人类智慧,考虑对于最后一次的乘法操作进行对齐,也就是说,对于翻倍次数最少的物品在最后一起翻 倍。所以,我们修改一下状态:令 \(f_{i, S}\) 表示在模 \(m\) 意义下 \(S\)(也就是说这个物品是否存在)。
接下来,我们考虑转移:
对于 \(f_{i, S}\) 可以转移到 \(f_{2i, S}\);
然后,对于任意一个,如果原来是没有的,转移到有的(也就是修改 \(S\) 在二进制下的意义);如果没有那就加上即可。反正这题很有意思。
-
P2371 [国家集训队] 墨墨的等式。
典中典。
考虑同余最短路。我们设 \(x\) 是所有 \(a\) 中不为零的任意一个数。接下来我们考虑对于 \([0, x - 1]\) 模数进行分组。所以,我们考虑 \(dis_i\) 表示模数为 \(i\) 是最小满足要求的解。
然后,我们考虑对于 \(i\) 向 \(i + a_j\) 连一条长度为 \(a_j\) 的一条边,然后跑最短路径即可。跑出来的答案就是满足答案的。
注意到这个答案可以进行前缀和,所以答案我们就可以用 \([0, r] - [0, l - 1]\) 即可。最后注意一下边界情况即可。
gml:这是一道很需要观察的题。
首先,我们注意到最大值一定是所有整数之和(我们记为 \(A\)),次大值一定是 \(A\) 加上一个大负数或者减掉一个小整数(我们记这个数是 \(B\))。那么,一定存在 \(|S_i| = A - B\)。我们设 \(A - B = d\)。
接下来,我们钦定 \(d > 0\),那么我们可以轻松把这个集合分裂成两个集合:一个叫做 \(S_1 = a + d, b + d
...\),另一个叫做 \(S_2 = a, b ...\)。
重复上述操作,直到剩下 \(2\) 个元素,我们设较小的是 \(M\)。我们再次注意力惊人一下,加入 \(M \ne 0\),那么必定存在 \(M < 0\)。但是,我们现在得到的数列相当于原集合 \(S\) 中所有元素的绝对值。那么,相当于我们需要在剩下的元素中选择一些当做负数,然后这个过程背包 DP 即可。最后再倒着回去即可。
Day 3
区间DP
- AT_abc273_f [ABC273F] Hammer 2。
考虑 DP。我们首先把所有的东西都给离散化,然后我们设 \(f_{l, r, 0/1}\) 表示处理了 \(a_l\) 到 \(a_r\) 之间的事情,最后停留在了 \(l\) 或者 \(r\)。
我们很轻松列出状态转移方程:
然后我们考虑对于不是墙的位置,这些转移是容易的。如果这是一堵墙,我们就判断相应的 \(Z_i\) 是否满足 \(a_l \le Z_i \le a_r\) 即可。复杂度是 \(O(n^2)\)。
-
P9119 [春季测试 2023] 圣诞树。
依旧简单题,和上面那个题状态转移方程一致。
首先,我们先考虑一些数学性质。
如果我们走一个交叉区间,那么根据三角形三边关系,我们很容易就知道交叉走一定劣于直着走。这是显然的。
然后就随手区间 DP 一下。记得要破环成链,然后记录一下 \(opt_{l, r, 0/1}\) 是从哪个位置转移过来的即可。
最后记得倒着找回去,复杂度 \(O(n^2)\)。 -
P7914 [CSP-S 2021] 括号序列。
我们首先考虑状态。很自然地,我们设 \(f_{l, r}\) 表示区间 \([l, r]\) 的方案数。
但是,我们发现我们并没有办法转移形如 \(SA\) 或者 \(AS\)。所以,我们设 \(4\) 个辅助状态(没这么少)。
先考虑:
-
\(p_{l, r}\) 是形如 (A) 的方案数;
-
\(L_{l, r}\) 表示形如 SA 的方案数;
-
\(R_{l, r}\) 表示形如 AS 的方案数;
-
\(ok_{l, r}\) 表示能否拼成连续的星号序列。
我们注意到 \(ok\) 数组其实是可以预处理的,所以我们
充分发扬人类智慧,考虑如果 \([l, r]\) 两边可以组成一个括号,也就是说这两个都是合法的,那么一定有 \(p_{l, r} = g_{l + 1, r - 1} + f_{l + 1, r - 1} + L_{l + 1, r - 1} + R_{l + 1, r - 1}\)。这里加一个特判,如果 \(l = r - 1\) 那么 \(p_{l, r} = 1\)。
接着考虑形如 SA 的格式。我们很容易得出,\(L_{l, r} = \sum ok_{l, k} \times L_{k + 1, r}\)。
最后是形如 AS 的格式,我们得出 \(R_{l, r} = \sum R_{l, k} \times ok_{k + 1, r}\)。
最后解决 \(f_{l, r} = p_{l, r} + \sum p_{l, k} \times (f_{k + 1, r} + L_{k + 1, r})\)。
gml:这题得分要不是 0 或者 100 的都是神人。
- AT_abc219_h [ABC219H] Candles。
类似于关路灯的好题。
我们设 \(f_{l, r, k, 0/1}\) 表示现在走过了 \([l, r]\) 的区间,此时有 \(k\) 个蜡烛正在燃烧,我们现在正处于 \(l\) 位置或者 \(r\) 位置。
人类智慧的,我们容易发现,如果最后的第 \(i\) 个蜡烛的得分一定是 \(\max (0, a_i - T)\)。假设我们现在是正数,但是我们加成了负数;如果是 \(0\),我们算成了负数,那么一定不优。所以我们直接对所有的可能取 \(max\) 即可。
所以,我们可以清晰地列出转移方程,直接考虑这个位置是否被燃尽即可。复杂度 \(O(n^3)\)。
- CF888F Connecting Vertices。
我们设 \(f_{l, r, 0/1}\) 表示 \([l, r]\) 之间是否存在 \(l\) 和 \(r\) 之间的直接连边的方案数。显而易见的,我们得出状态转移方程:
树形DP
- P4516 [JSOI2018] 潜入行动。
我们设 \(f_{u, j, 0/1, 0/1}\) 表示 \(u\) 位置放置了一共 \(j\) 个监听设备,第 \(u\) 个位置是否放置了监听器、这个位置是否被监听。
接下来我们考虑:
- 如果 \(u\) 既没有监听装置、也没有被监听,我们知道 \(f_{u, i + j, 0, 0} = \sum f_{u, i, 0, 0} \times f_{v, j, 0, 1}\);
- 如果 \(u\) 有监听装置,但是m没处于监听状态,我们很容易知道 \(f_{u, i + j, 1, 0} = \sum f_{u, i, 1, 0} \times (f_{v, j, 0, 0} + f_{v, j, 0, 1})\);
- 如果 \(u\) 没有监听装置,但是有被监听,我们分两种情况:\(f_{u, i + j, 0, 1} = \sum f_{u, i, 0, 1} \times (f_{v, j, 0, 1} + f_{v, j, 1, 1})\),或者是 \(f_{u, i + 1, 0, 1} = \sum f_{u, i, 0, 0} \times f_{v, j, 1, 1}\);
- 如果 \(u\) 既有监听装置,也同时被监听,则分两种情况:\(f_{u, i + j, 1, 1} = \sum f_{u, i, 1, 1} \times (f_{v, j, 0, 0} + f_{v, j, 1, 0} + f_{v, j, 0, 1} + f_{v, j, 1, 1})\) 或者是 \(f_{u, i + j, 1, 1} = \sum f_{u, i, 1, 0} \times (f_{v, j, 1, 0} + f_{v, j, 1, 1})\)。
- CF1499F Diameter Cuts。
有意思。
我们设 \(f_{u, j}\) 表示 \(u\) 节点往下延伸最深是 \(j\) 深度的方案数。
然后,我们考虑 \(v\) 的转移方程:
对于第一个式子,必须满足 \(i + j + 1 \le k\)。答案为 \(\sum_{0 \le i \le k} f_{1, i}\)。
- P8867 [NOIP2022] 建造军营。
首先我们进行 tarjan 求出边双连通分量。对于每一个边双,我们设 \(E_u\) 表示这里面有多少条边,\(siz_u\) 表示 \(u\) 以下的子树的边(包括割边)的数量。
设 \(f_{u, 0/1}\) 表示 \(u\) 是否放置军营。考虑状态转移:
然后统计答案是 \(\sum f_{u, 1} \times 2^{m - siz_u - 1}\)。
Day 4
状压 DP
-
题意简述:有 \(n\) 个村庄,然后这些村庄有边相连,求出遍历这些村庄的最小代价。
考虑状态压缩 DP。设 \(f_{S, i}\) 表示走遍状态为 \(S\) 的村庄,最后停留在了 \(i\) 的最小代价。
接下来枚举 \(j\),使得 \(j \notin S\),所以 \(f_{S \cup j, j} = \min_{i \in S} f_{S, i} + dis(i, j)\)。
虽然老师讲的很抽象,但是 deepseek 真有意思!向伟大的 deepseek 致敬!
首先我们注意力惊人一下,发现这个东西最后的形状一定是一个从左下角到右上角的一条折线,并且每一步折线只能向右或者向上。
我们注意到一共的状态数量是 \(C_{n + m}^{n}\) 种状态,所以我们考虑状态压缩。
对于这个棋盘进行编码,我们用 \(0\) 表示向右走,\(1\) 表示向上走。我们充分发扬人类智慧发现,每一步落子只能在 \(01\) 拐角的位置。所以说,每一次进行操作之后,相当于将 \(01\) 翻转为 \(10\)。
所以我们设 \(f_S\) 表示目前为 \(S\) 的最优策略,如果发现 \(i\) 是 \(0\),\(i + 1\) 是 \(1\),那么就可以翻转。我们设此时的状态是 \(S'\)。则我们转移方程 \(f_{S'} = \max f_{S} + val\),其中 \(val\) 是此时的代价,根据奇偶性判定此时是 \(a_{i, j}\) 还是 \(-b_{i, j}\)。
-
P7519 [省选联考 2021 A/B 卷] 滚榜。
先考虑最简单的做法。我们设 \(f_{S, i, j, k}\) 表示集合 \(S\) 中最后一个人是 \(i\),用了 \(\sum b = j\),上一个人选择的是 \(k\) 的方案数。注意到我们这样的做法复杂度是比暴力阶乘还要慢,考虑优化,
我们注意到其实我们并不关心 \(b_i\) 的具体排列方式,只关心的是存在多少种排列方法。所以,我们搞出差分数组:\(c_i = b_i - b_{i - 1}\)。然后,\(m = \sum b_i = \sum c_i \times (n - i + 1)\)。我们期望 \(a_i\) 变成了最大值,很容易知道 \(c_i\) 其实就是我们想要的。所以,这样我们就可以省掉了一维的状态。
一道神奇题目。
我们先考虑 \(\sqrt n\) 怎么处理。
我们注意到这里的质数个数并不多,所以我们考虑状态压缩。我们设 \(f_{i, S1, S2}\) 表示前 \(i\) 个点,A 选择的集合是 \(S1\),B 选择的集合是 \(S2\)。之后所有的答案是 \(S1\) 和 \(S2\) 没有交集。
接下来我们注意到至多存在一个质因数大于 \(\sqrt n\),所以我们还是进行状态压缩。把相同的一个质因数归为一类,重复上面的过程即可。
- P9479 [NOI2023] 桂花树。
好题!
首先,我们发现,多出来的点一共只有3种选择,分别是:
-
接在任意一个点的下面;
-
把一条边拆成两条,接在中间;
-
把一条边拆成两条,同时在新的点上接上一个点。
我们注意力惊人,会发现前面两种方式并不会更改树的 LCA 的格式。所以,我们考虑每一个点(按照顺序一个一个加入),此时我们设 \(f_{i, S}\) 表示考虑到 \(i\) 这个点,此时后面 \(k\) 个点(\([i + 1, i + k]\))之间,有哪些点需要补上,然后再进行 DP 即可。更有意思的是,这个题和 \(T\) 的形状没有任何关系。
好了,这题就这么做。
wxh:我能进国家集训队!
- P6622 [省选联考 2020 A/B 卷] 信号传递。
我们设 \(f_S\) 表示答案。
我们先先把贡献拆到每一位。也就是说,我们设 \(w_{i, j}\) 表示 \(i\) 到 \(j\) 的次数。此时,我们可以计算出 \(w_{i, j} \times val\) 得到此时的贡献。
接下来,我们考虑提前计算贡献。\(g_{S, i}\) 表示把 \(i\) 扔进去 \(S\) 之后进行重排的 cost,我们很容易发现枚举一个 \(j\),但是我们注意到其实只计算 \(i\) 的贡献的话,这样我们可以得出,只要进行一些加加减减的操作(gml 原话)即可。
然后,我们注意到爆空间了。那么。我们注意到 \(S\) 中含有 \(i\) 是没有意义的,所以这样我们可以把 \(S\) 少压缩一个数即可。
最后,\(f_{S \cup{i}} = f_{S} + g_{S, i}\)。
换根 DP
- P3478 [POI 2008] STA-Station。
小小简单题。我们考虑设 \(f_u\) 表示以 \(u\) 为根时的答案。
接下来,我们列出状态转移方程:\(f_u = f_{father} + n - 2 \times siz_u\)。
然后 DFS 一下就做完了。
Day 5
插头 DP
-
P5056 【模板】插头 DP。
老师讲的好抽象,还好 luogu 有题解。
我们先定义一下什么叫做插头。
我们对于一条路径联通两个相邻的格子我们就叫做插头。
接下来,我们注意力惊人,发现每个格子存在度数是 \(2\)。这是显然的。接下来,我们发现,只考虑插头是不够的,必须考虑插头之间的连通性。形式化的,我们设靠近左边的插头叫做 (,靠近右边的记为 ),如果这里没有插头我们记为 \(0\)。注意到任意一个合法的插头都能够表示成一个合法的括号序列。
接下来,我们开始搞抽象,考虑对于合法的括号序列改成数字。我们设 \(1\) 表示左括号,\(2\) 表示右括号,\(0\) 表示没有插头。为了便于计算,我们把这个视作一个四进制数字。
接下来,我们对于四进制数字进行计算,每次考虑插头是向上移动或者向右移动。最后我们合并计算即可。
复杂度是 \(O(nmV)\),其中 \(V\) 表示状态个数。 -
P3886 [JLOI2009] 神秘的生物。
注意到这里的连通性和前一个题并不一致,所以我们不能使用括号表示法。
所以,此时我们采取一个叫做最小表示法的东西表示每一个状态。
我们还是考虑对于每一个联通块,我们设 \(1, 2...\) 这些分别表示每一个连通块,用 \(0\) 表示空的插头。此时唯一需要注意的就是我们转移了之后必须还是保证字典序最小。这样我们就可以大大简化了我们的状态数量。
注意到这里 \(\frac{9}{2} = 4.5\),所以我们考虑状态数是 \(5\),所以我们使用八进制数字进行表示。
然后就是方程转移了。 -
P3290 [SCOI2016] 围棋。
正难则反。考虑容斥。
我们设 \(f_{i, j, S, x, y}\) 表示在位置 \((i, j)\) 的轮廓线状态为 \(S\),此时第一行匹配上了 \(x\) 个位置、第二行匹配上了 \(y\) 个位置。
接下来,我们考虑 KMP。我们枚举此时的状态,并且通过 KMP 计算出了新的 \(x\) 和 \(y\)。考虑轮廓线的状态,这个状态是 \(1\) 当且仅当此时的已经匹配到了这个位置。所以我们考虑如果 \((i, j - 1)\) 是 \(1\) 那么 \((i, j)\) 一定不是。此时特判即可。结合 KMP,我们即可求解。
数位 DP
-
P13085 [SCOI2009] windy 数(加强版)。
我们设 \(f_{pos, lst, 0/1, 0/1}\) 表示我们现在考虑第 \(pos\) 位,上一位的数字是 \(lst\),现在是否是在上界,现在是否还是前导零。我们可以根据此进行记忆化搜索。复杂度虽然看似很高,实则很低。比较套路化的一道题。 -
P6669 [清华集训 2016] 组合数问题。
一看就是 zhx 出的好题。
考虑 Lucas 定理。
所以,上面的式子我们考虑变形:如果我们记 \(a_i\) 表示 \(n\) 的第 \(i\) 位,\(b_i\) 表示 \(m\) 的第 \(i\) 位(考虑在 \(k\) 尽职意义下)。
所以,上面的式子我们可以写成:
然后我们发现,只需要存在一个 \(a_i < b_i\) 上面式子的右边就是 \(0\)。此时满足要求。
所以我们考虑数位 DP。显然的,我们设 \(f_{pos, ok, dif, lim1, lim2}\) 分别表示考虑第 \(pos\) 位,此时 \(i\) 和 \(j\) 是否发生了 \(i < j\),\(i\) 和 \(j\) 是否发生了差异,此时的 \(i\) 是否还在上限,\(j\) 是否还在上限。记忆化搜索即可。
浙公网安备 33010602011771号