2024.6 and 2024.7 做题记录
1.#2498. Xavier is Learning to Count
有 \(n\) 个互不相同的整数 \(a_{1, \cdots, n}\),从其中任取恰好 \(k\) 个数,记他们和为 \(s\),求对于每个 \(s\) 的方案数。
\(n, a_i\le 1.3 \times 10^4, k \le 5\)。
根据互不相等容斥的结论,只需枚举集合划分的方案 \(\{S_i\}\),钦定同一个集合中的数全部相等,容斥系数为 \((-1)^{\lvert S_i \rvert - 1} (\lvert S_i \rvert - 1)!\)。
现在只需考虑枚举了一个集合划分 \(\{ S_i \}\),然后求它的方案数。
预处理出 \(F_i(x)\) 表示选出 \(i\) 个相同的数的生成函数,和为 \(m\) 的答案即为:
先 DFT,然后在点值下做完,最后 IDFT 回去就行。
时间复杂度 \(O(nk(\operatorname{Bell}(k) + \log n))\)。
2.P4717 【模板】快速莫比乌斯/沃尔什变换 (FMT/FWT)
/fendou
3.#310. 【UNR #2】黎明前的巧克力
开摆。
4.Another MEX Problem
首先可以列出 dp:\(f_{i, j}\) 表示前 \(i\) 个数凑出 \(j\) 是否可行。
转移显然。
下面有两种优化方法。
solotion1
考虑哪些转移是有用的。
发现我们只需要极小 \(\operatorname{mex}\) 区间,而这个是 \(O(n)\) 个的。
所以预处理出来有效转移就做完了。
时间复杂度 \(O(n^2)\)。
solution2
dp 数组只表示可行性太浪费,所以不妨改为 \(f_i\) 表示凑出 \(i\) 的最小右端点。
dp 的初值可以 \(O(n^2)\) 算出。
转移考虑按 \(f_i\) 从小往大的顺序转移(本质上是在做一个最短路),发现我们需要 \(g_{i, j}\) 表示 区间 \([l, r]\) 满足 \(l \ge i\) 且 \(\operatorname{mex}(l, r) = j\) 的最小的 \(r\)。
这个也是可以 \(O(n^2)\) 预处理的。
转移是:
时间复杂度 \(O(n^2)\)。
5.P9970 [THUPC 2024 初赛] 套娃
首先有一个结论:极短 \(\operatorname{mex}\) 段只有 \(O(n)\) 个。
证明大概是,记 \(cnt_i\) 表示 \(i\) 的出现次数,从小到大枚举 \(\operatorname{mex} = x\),假设已经求出了 \(\operatorname{mex} = x - 1\) 时的极短 \(\operatorname{mex}\) 区间,那么把序列按 \(x\) 分段,每个 \(x\) 只会和它左右两边最近的 \(x - 1\) 的极短 \(\operatorname{mex}\) 区间配对,跨过 \(x\) 的可以看成是从 \(x - 1\) 继承的,所以 \(x\) 对个数的贡献是 \(2(cnt_x + 1)\),总个数为 \(O(\sum cnt_i) = O(n)\)。
首先类似上面的证明的过程求出极短 \(\operatorname{mex}\) 区间。
发现对于一个极短的 \(\operatorname{mex} = x\) 的区间,我们可以求出它对应的极长 \(\operatorname{mex}\) 区间,记它们的长度分别为 \(l, r\),那么他们就会对 \(b_{l, r}\) 有 \(x\) 的贡献。
所以不妨从大到小枚举 \(\operatorname{mex} = x\),每次把不会被它贡献到的区间的答案推平为 \(x\),就做完了。
时间复杂度 \(O(n \log n)\)。
6.P10169 [DTCPC 2024] mex,min,max
看到 \(\min\) 和 \(\operatorname{mex}\) 同时出现,首先回忆一下如何 \(O(1)\) 区间 \(\operatorname{mex}\),然后发现 \(\min\) 和 \(\operatorname{mex}\) 一定恰好有一个 0。
分类讨论:
- \(\operatorname{mex} = 0\):
此时区间中一定不包含 0,即序列被 0 划分成了若干段,我们只需依次考虑每一段即可。
对于一个极长非 0 段,我们对它扫描线,由于区间极差具有单调性,所以只需二分出最长的满足要求的后缀即可。 - \(\min = 0\):
此时 \(\operatorname{mex}\) 一定不等于 0,有一个结论是极短 \(\operatorname{mex}\) 区间有 \(O(n)\) 个,所以我们枚举每个极短 \(\operatorname{mex}\) 区间,找到它对应的极长 \(\operatorname{mex}\) 区间,由于最大值有单调性,所以可以二分出对应的答案区间。
这里可能会出现同一个区间被统计多次的问题,所以要把答案区间记下来放到二维平面上做矩形面积并。
时间复杂度 \(O(n \log n)\)。
7.Odd Mineral Resource
看到出现奇数次想到异或,但是这很容易卡。
所以对每个数随机映射到另一个数上去,这样错误率就比较低了。
然后判定可以用异或和不为 0,找数可以主席树上二分。
时间复杂度 \(O((n + q) \log n)\)。
8.P4197 Peaks
第一想法是先 Kruskal 重构树然后线段树合并,仔细想想发现主席树就好了。
时间复杂度 \(O(n \log n)\)。
9.P5043 【模板】树同构([BJOI2015]树的同构)
。
10.P7219 [JOISC2020] 星座 3
首先让 \(a_i \leftarrow n - a_i\),\(y_i \leftarrow n - y_i + 1\),这样能放星星的位置就是若干个最下端在同一条线上的矩形了。
条件等价于每个子矩形都至多能放一个星星,不难发现只有极大的矩形有用,也就是你做单调栈的时候产生的那几个,所以考虑建出笛卡尔树在笛卡尔树上做。
考虑 dp:设 \(f_{u, i}\) 表示 以点 \(u\) 为根的子树中深度最浅的星星的深度为 \(i\)。
转移为:
发现第一个转移是可以把 \(j\) 的取值范围改为 \(j > a_u\) 的,因为我们是在笛卡尔树上 dp 的,后面的过程中只关心后缀最大值。
可以用线段树合并优化。
时间复杂度 \(O((n + m) \log \max c_i)\)。
11.A. travel
发现环排列的情况是更简单的,先考虑环排列。
Part1 op = 2
先考虑上下界。
下界显然是按照欧拉序走,每条边恰好经过两次,所以是 \(2(n - 1)\)。
上界考虑对每条边计算贡献。设它两边的子树大小分别为 \(sz_1\)、\(sz_2\),那么这条边的贡献至多是 \(
min(sz_1, sz_2)\),对这个东西求和便是上界。
\(k\) 为奇数是显然无解,因为是环排列,所以一条边如果通过它走到了另一棵子树中,那么一定是会走回来的,所以每条边的次数都是偶数,那么 \(k\) 也应是偶数。
猜测对于在上下界之间的 \(k\) 在 \(k\) 为偶数的时候一定有解。
考虑构造上界。
先写出对于一个环排列 \(p\) 的贡献:
前面的式子的值是一定的,想要让它取到上界,只能让后面的式子为 0。
这就是在说让我们选一个跟,然后对于环排列中每对相邻的数,它们的 \(\operatorname{lca}\) 为根。
也就是在说,对于环排列中每对相邻的数,它们都不在同一个子树中。
这样树上两两匹配的构造有个常见的做法,就是取重心为根。
这样的好处就是没有一个子树的 \(size\) 大于点数的一半,也就是我们一定能构造出满足条件的排列。
构造方式是:第一个位置放根,然后每次取子树 \(size\) 最大的子树,将这棵子树中的一个节点加入到环排列中,直到所有点都被加入时停止。这样做能保证任意时刻没有子树 \(size\) 大于点数的一半,从而能保证一定能构造出解。
然后考虑从上界的构造方式调整到我们需要的 \(k\)。
考虑怎么做能够让我们当前的 \(k\) 减小,发现只需将两个在同一子树中的点合并到一起,记这两个点分别为 \(u\)、\(v\),这样会使答案减少 \(2 \times dep_{\operatorname{lca}(u, v)}\)。
不放对每棵子树的点按照 \(dfn\) 排序,然后每次选两个相邻的点按照上面的方法缩,最后会缩成若干个区间。这样的好处是在我们把子树缩成一个区间时,答案恰好时下界 \(2 \times (size - 1)\)。
考虑怎么让答案恰好为 \(k\)。
把点按照深度序,从大向小合并。当我们发现再缩一次答案就会小于 \(k\) 时,可以直接根链上找到一个没合并过的点满足合并它的代价恰好可以使得答案变为 \(k\),而且由于我们是按深度从大向小合并的,所以根链上的点一定没有被缩过,所以一定能找到这个点。
由于要保证有解,所以每次要找到剩余区间数最多的子树去缩,以保证任意时刻没有子树 \(size\) 大于点数的一半。
解的构造方式同上。
排序什么的可以桶排,所以时间复杂度是线性的。
Part2 op = 1
考虑从环排列的情况进行修改来得到构造。
此时相当于环排列的答案减去 \(\operatorname{distance}(p_1, p_n)\),所以下界为环排列的下界减去直径,上界为环排列的上界减一。
由于 \(\operatorname{distance(p_1, p_n)}\) 奇偶性不固定,所以猜测对于上下界中的每个数都有解。
先考虑 \(k < 2 \times (n - 1)\) 的情况,此时是小于环排列的情况的下界的。
记 \(k' = \operatorname{distance}(p_1, p_n) = 2 \times (n - 1) - k\),我们只需在环排列下界的情况下找到两个点 \(u\)、\(v\) 满足 \(\operatorname{distance}(u, v) = k'\),然后把环排列这两个点之间断开即可。
这两个点显然可以在直径上找,可以构造点 \(u\) 为直径的一端,点 \(v\) 为直径上与 \(u\) 距离为 \(k'\) 的点。
构造方式为从 \(v\) 开始 dfs,优先遍历不在 \((u, v)\) 这条链上的点,然后再遍历到 \(u\) 时停止即可。
再考虑 \(k \ge 2 \times (n - 1)\) 的情况,此时是不小于环排列的情况的下界的。
我们可以先用 \(op = 2\) 的方式构造出 \(k' = k + 2 - (k \bmod 2)\) 的一组解,我们只需在距离为 \(2 - (k \bmod 2)\) 的点对间断开即可。现在的问题是如何让构造出的环排列中有距离为 \(1\) 或 \(2\) 的相邻点对。
先考虑构造距离为 1 的相邻点对。发现根(重心)与它的一个儿子间的距离为 1,所以我们在第一次选区间放入环排列的时候可以先选根的儿子所在的区间,最后把根放到排列的最后即可。
再考虑构造距离为 2 的相邻点对。发现根(重心)的两个儿子间的距离为 1,所以我们在前两次选区间放入环排列的时候可以先选根的儿子所在的区间,最后把第一个选的区间 reverse 并在它们之间断开即可。
时间复杂度线性。
注意到上面的部分讨论都是在选出重心后至少有两个儿子的情况下讨论的,所以先把 \(n \le 2\) 判掉是个不错的选择。
总时间复杂度线性。
12.M. A + B Problem
贪心。依次扫描 \(s\),看填到哪个字符串中的结果会更优就填哪个。
时间复杂度 \(O(n \log n)\)。
13.P8253 [NOI Online 2022 提高组] 如何正确地排序
先考虑 \(\min\) 的情况,\(\min\) 的情况每个数取反就是 \(\max\) 的情况。
对于 \(m < 4\) 的情况,我们可以先用 \(+ \infty\) 补成 \(m = 4\) 的情况。
现在问题就变成了:
考虑对 \(\min\) 中分别取到每个数的时候统计答案。
不妨设 \(\min\) 中取到了 \(a_{1, i} + a_{1, j}\),我们看一下要满足什么条件。
移项可得:
是三维偏序的形式,可以直接做。
对于取到其他项的情况是类似的,为了保证每个数只会被统计到一次,只需将其中一部分小于等于改为小于即可。
时间复杂度 \(O(n \log^2 n)\)。
14.J. Carpets Removal
首先求 \(f_i\) 表示只被 \(i\) 地毯覆盖的点数。
那么对于所选地毯无交的情况,答案就是 \(f\) 的最大值和次大值之和。
对于有交的情况,最多只会影响 \(O(m^2)\) 对地毯的答案,所以考虑枚举格子依次判断会被哪两个地毯覆盖。
二位前缀和维护 每个位置的覆盖次数,覆盖它的地毯的编号和,编号平方和 即可求出答案。
时间复杂度 \(O(n + m^2 \log n)\)。
15.E - Water Distribution
我们一定是把整张图划分成若干个连通块,然后每个联通块选一个森林。
不妨设每个连通块的点权和为 \(s_1\),边权和为 \(s_2\),点数为 \(n\),那么这个连通块的贡献就是 \(\frac{s1 - s2}{n}\)。
所以 \(O(2^nn^2 \log n)\) 预处理出所有连通块的贡献,\(O(3^n)\) 子集 dp 即可。
时间复杂度 \(O(2^nn^2 \log n + 3^n)\)。
16.P4719 【模板】"动态 DP"&动态树分治
\fendou
GBT 比树剖快了 7 倍 /oh
17.Colorful Stones
首先发现合法的部分一定是贪心的找到边界后删掉几个格子。
画一画发现格子只有 \(s_{i - 1} = t_j \and s_{i} = t_{j = 1}\) 时是不合法的。
所以扫描线维护边界前缀和即可。
时间复杂度 \(O(n \lvert \sum \rvert ^2)\)。
18.P6573 [BalticOI 2017] Toll
分治最短路。
时间复杂度 \(O(n k^2 \log^2 n)\)。
19.P5024 [NOIP2018 提高组] 保卫王国
首先有:
然后求最大独立集就是板子了。
强制选和不选可以用赋值 \(\infty\) 来完成。
时间复杂度 \(O(n + q) \log n\)。
20.P3781 [SDOI2017] 切树游戏
先考虑没有修改的情况。
设 \(F_u\) 表示 以点 \(u\) 为根的答案的生成函数,\(G_u\) 表示以 \(u\) 为根的子树的生成函数。
那么有:
其中乘法是异或卷积。
对每个点的生成函数预处理出 FWT 值即可做到 \(O(nm)\)。
有询问的情况考虑 DDP,把转移写成矩阵的形式。
记 \(F'_u\) 表示 以点 \(u\) 为根除去重儿子的答案的生成函数,\(G'_u\) 表示以 \(u\) 为根的子树的生成函数。
记 \(s_u\) 表示 \(u\) 的重儿子,那么有:
然后 GBT 维护即可。
对于矩阵的维护,实际上只有四个位置的值是会变化的,所以只用维护这四个位置的值。
时间复杂度 \(O(nm \log n + qm \log n)\)。
21.P5367 【模板】康托展开
。
22.P6086 【模板】Prufer 序列
/fendou
23.P5495 【模板】Dirichlet 前缀和
/fendou
24.P5056 【模板】插头 DP
/fendou
25.P4783 【模板】矩阵求逆
/fendou
26.P8819 [CSP-S 2022] 星战
条件等价于判断是否每个点出度都为 1。
由于操作都是对入度进行的,所以判断出度是不好做的,好做的是判断入度。
所以对每个点随机赋值为 \(w_u\),对于一条边 \((u, v)\),我们认为它的权值为 \(w_u\)。
最后只需判断边权之和是否为 \(\sum_u w_u\) 即可。
时间复杂度 \(O(n)\)。
27.P8820 [CSP-S 2022] 数据传输
设 \(f_{u, 0 / 1 / 2}\) 表示 走到与点 \(u\) 距离为 \(0 / 1 / 2\) 的点的最少花费。
对 \(k\) 分类讨论。
\(k = 1\)
等价于路径上点权和。
不过为了和后面的形式保持一致这里就写成矩阵的形式:
\(k = 2\)
发现只会经过路径上的点及与其相连的点。
记 \(val_u\) 表示与 \(u\) 相连的点中最小的点权。
转移不难直接写出:
\(k = 3\)
基本同 2。
转移为:
然后倍增维护双向矩阵乘积即可。
时间复杂度 \(O((n + m) k^3 \log n)\)。
28.P7077 [CSP-S2020] 函数调用
如果只有 1、 2 两种类型的操作,那么有一种做法就是对每个点维护加法 tag 和全局乘法 tag。
再考虑加上 3 操作。
还是考虑把每个点变成 \(a_i \leftarrow mult \times a_i + add_i\) 的形式。
全局乘法标记是好做的,现在要做的是维护每次加法操作的实际值。
不放先把函数调用关系建成图。
先预处理出每个点调用后的全局乘法 tag,然后按拓扑序 dp 就能得到加法操作的真实值。
时间复杂度线性。
29.P9755 [CSP-S 2023] 种树
什么傻逼题。感觉出题人双亲被宇宙射线轰炸过了。
30.P5665 [CSP-S2019] 划分
显然最后一段越小越优。
那么设 \(pre_i\) 表示 \(i\) 最大的能转移到的位置,这个可以单调队列简单维护。
最后统计答案即可。
时间复杂度线性。
31.P7116 [NOIP2020] 微信步数
无解是好判的。
考虑把 \(\prod w_i\) 个点一起移动,将每次能使这次移动合法的点加起来就是答案。
先考虑第一个周期。对于每一维,ban 掉的点一定是一段前后缀。所以我们处理出每天每一维左右方向的最大位移 \(L_{i, j}\)、\(R_{i, j}\),那么答案为:
不难发现,除了第一个周期,其余周期 ban 掉的人数是相等的。
这个是可以预处理的,记为 \(cnt_{i, j}\) 表示前 \(i\) 天第 \(j\) 维 ban 掉的点数。
那么对于第 \(x\) 个周期,它的答案为:
我们不妨枚举天数,对每一天分别计算共享。
对于第 \(i\) 天,我们能算出它能进行多少个周期:
我们改写 \(f(x)\) 的定义为第 \(i\) 天第 \(x\) 个周期的贡献,这样就可以把除掉第一周期的贡献算出:
不难发现这是个至多 \(k + 1\) 次的多项式,拉格朗日插值即可。
时间复杂度 \(O(nk)\)。
32.Close Vertices
邻域数点,考虑点分治。
现在要做的是统计跨重心的贡献,这实际上是个二维偏序,同子树的再做一遍减掉就好。
时间复杂度 \(O(n \log^2 n)\)。
33.P3747 [六省联考 2017] 相逢是问候
肯定要用到扩展欧拉定理:
算一下发现 \(\varphi(p)\) 最多复合 28 层就会变成 1,也就是说对每个位置,1 操作执行至多 28 次后值就不会再改变。
所以我们可提前预处理出 \(a_i\) 执行 \(j\) 次 1 操作后的值为 \(a_{i, j}\),这部分注意求 \(c^k\) 时使用光速幂。
然后线段树上维护区间和、区间最小执行操作 1 次数,每次修改时找到每个没达到修改次数上限的位置暴力修改即可。
时间复杂度 \(O(n \log^2 p)\)。
34.Dances (Hard Version)
先考虑只有一个 \(c\) 数组的情况。
我们删数的策略是将 \(c\)、\(b\) 分别排序,\(c\) 删一段后缀,\(b\) 删一段前缀。
删多少个可以二分。
发现每个 \(c\) 数组不同的数只有 1 个,所以答案之差不会超过 1,因为可以直接把不同的这个数删掉。
而且如果记 \(c_1 = 1\) 时的答案为 \(ret\),那么答案为 \(ret\) 和答案为 \(ret + 1\) 的分别是一段前缀和剩下的后缀。
所以可以二分分界点,check 可以用上面的那个二分。
时间复杂度 \(O(n \log^2 n)\)。
35.Résumé Review
记 \(f_i(x) = x(a_i - x^2)\)。
先求个导:\((-x^3 + ax)^{'} = -3x^2+a\)。
不难发现 \(f(x)\) 是凸的,且 \(\Delta f(x)\) 是单调递减的。
所以我们的思路是每次找到 \(\Delta f_i(x)\) 最大的 \(i\),把 \(b_i\) 加一。
考虑二分一个 \(t\) 使得 \(\Delta f_i(x) \le t\) 的 \(x\) 的和小于等于 \(k\)。
这个是简单的。
然后每个位置微调即可。
时间复杂度 \(O(n \log^2 V)\)。
36.Tourist
直接 DP。
37.P6189 [NOI Online #1 入门组] 跑步
首先答案是分拆数。
有一种做法是 MTT,不过还有简单做法。
先根号分治,发现 \(\ge \sqrt n\) 的数最多选根号个,\(\le \sqrt n\) 的数只有根号个。
所以可以设计两个 DP:\(f_{i, j}\) 表示用 \(\le i\) 的数拼出 \(j\) 的方案数,\(g_{i, j}\) 表示用 \(\ge i\) 的数拼出 \(j\) 的方案数。
时间复杂度 \(O(n \sqrt n)\)。