2025.10 做题记录
2025.10 做题记录
10.1
CF1065G - Fibonacci Suffix (观察性质 + 逐位确定 + DP 刻画)
考虑逐位确定答案
设当前已确定的答案串为 \(\text{ans}\),先尝试在末尾拼个 0,统计 \(F(n)\) 中有多少个后缀 \(\le \text{ans}\)
考虑用 DP 刻画
令 \(f_i\) 表示 \(F(i)\) 中有多少个后缀 \(\le \text{ans}\);为辅助转移,再令 \(g_{i, j}\) 表示拼接 \(F(i), F(j)\) 时新产生多少个后缀 \(\le \text{ans}\)
显然有转移 \(f_{i} \leftarrow f_{i-2}+f_{i-1}+g_{i-2, i-1}\);问题只在于如何求出 \(g_{i-2, i-1}\)
P.S. 此处 " \(\le\) " 的定义为前 \(|\text{ans}|\) 位字典序 \(\le\)
注意到 \(|F(12)|, |F(13)| > 200\),当 \(i \ge 14\) 时,长度 \(\le m\) 的前 / 后缀不会跨过前两个串的连接处
这个性质的用处在于,拼接 \(F(i-1), F(i)\) 时 ( \(i-1 \ge 14\) ):
- 新产生的 \(\le \text{ans}\) 的后缀的前 \(m\) 位在 \(F(i-1)\) 中的部分必定来自 \(F(i-2)\)
- 新产生的 \(\le \text{ans}\) 的后缀的前 \(m\) 位在 \(F(i)\) 中的部分必定来自 \(F(i-2)\)
- 综上,有 \(g_{i-1, i} = g_{i-2, i-2}\)
预处理 \(l_{12} = r_{12} = 12, l_{13} = r_{13} = 13\) 且 \(l_i = l_{i-1}, r_i = r_{i-2}\ (i \ge 14)\),则 \(g_{i, j} = g_{l_i, r_j}\ (i, j \ge 14)\)
预处理 \(g_{12/13, 12/13}\) 与 \(f_{12}, f_{13}\) 即可;单次时间复杂度 \(O(m^2)\),瓶颈在预处理
综上,当 \(n \le 13\) 时暴力求,反之 DP 即可;最终值 \(<k\) 则改为拼上 1,\(>k\) 则拼上 0,\(=k\) 则拼上 0 并输出
时间复杂度 \(O(nm^2)\),常数很小
CF587F - Duff is Mad (离线差分 + SA - 树状数组维护 \(\text{h}_i\) 连续段 + 根号分治)
套路的用特殊字符隔开全拼起来,建 SA 维护子串出现次数
先对询问离线差分,即将 \([l, r]\) 变为 \([1, r] - [1, l-1]\)
枚举串编号 \(i\),设其在总串中起始位置为 \(\text{st}_i\);考虑令 \(\text{h}_{\text{st}_i}\) 所在极长连续段区间 \(+1\),树状数组维护即可
法 1:查询 \(s_k\) 时,枚举 \(s_k\) 中每个位置 \(i\) 对应的 \(\text{rk}_i\),在树状数组中查询
法 2:开 vector 记录 \(s_k\) 中每个 \(\text{rk}_i\),每次二分在区间内的第 \(1\) 个 \(\text{rk}_i\) 与最后 \(1\) 个 \(\text{rk}_i\) 的位置 \(l, r\),累加 \(r-l+1\)
考虑根号分治;用法 1 解决 \(|s_i| \le B\) 的串,法 2 解决剩下的串
法 1 时间复杂度 \(O(qB \log n)\),法 2 时间复杂度 \(O(\frac{n^2 \log n}{B})\)
由于 \(n, q\) 同阶,取 \(B = \sqrt n\) 时最优,总时间复杂度 \(O((n+q) \sqrt n \log n)\)
CF1789F - Serval and Brain Power (分讨 - DP 求 LCP / 枚举贪心)
法 1:
考虑枚举分隔点,将串 \(s\) 分成 \(k\) 段,对 \(k\) 段同时 DP 求 \(\text{lcp}\)
时间复杂度 \(O(\binom{n}{k-1} n^k)\),很松
当 \(k \le 3\) 时,可以使用这个做法
法 2:
显然,\(\text{lcp}\) 必然被至少 \(1\) 个长为 \(\lceil \frac{n}{k} \rceil\) 的子串完全包含
枚举子串起点 \(i\),暴力 \(2^{\lceil \frac{n}{k} \rceil}\) 枚举后面的字符的选择状态,再从头贪心匹配 check 即可
时间复杂度 \(O(n^2 2^{\lceil \frac{n}{k} \rceil})\)
当 \(k \ge 5\) 时,可以使用这个做法
P.S. 容易发现 \(k\) 增大时,子串长度 \(\lceil \frac{n}{k} \rceil\) 减小,于是只需按照 \(k = 5\) 实现即可
注意到 \(k = 4\) 的情况完全包含于 \(k = 2\),那么做完了
10.2 - 10.3
摆烂 + 做 whk 作业
10.4
P12038 [USTCPC 2025] 送温暖 (分讨重心 + 子树分类 + meet in the middle)
看到 \(n \le 33\),考虑 meet in the middle
这启示我们分讨重心,因为以重心为根时子树大小 \(\le \frac{n}{2}\):
-
当连通块不包含重心时,对每个子树 \(2^{\text{siz}}\) 暴力枚举即可
这部分时间复杂度 \(O(n2^{\frac{n}{2}})\),很松
-
当连通块包含重心时,有结论:必能将根的所有儿子划分为两集合 \(S, T\),使得 \(\max \{\sum\limits_{u \in S} \text{siz}_u, \sum\limits_{v \in T} \text{siz}_v\} \le \frac{2}{3}n\)
\(\text{deg}_\text{rt} \le 3\) 时,由抽屉原理,必有一儿子 \(v\) 满足 \(\text{siz}_v \ge \frac{1}{3}n\);将 \(v\) 划分进 \(S\),其他划分进 \(T\) 即可
\(\text{deg}_\text{rt} > 3\) 时,取出 \(\text{siz}\) 最小与次小的两儿子 \(v_1, v_2\),必有 \(\text{siz}_{v_1} + \text{siz}_{v_2} \le \frac{n}{2}\);合并 \(v_1, v_2\),\(\text{rt}\) 仍为重心,归纳证明即可
按照如上过程将儿子分类,对一侧 \(2^\text{siz}\) 枚举所有含根连通块,用 set 维护
暴搜另一侧,分讨是否需要 \(-m\),在 set 里 lower_bound 即可
时间复杂度 \(O(n2^{\frac{2}{3}n})\)
综上,总时间复杂度 \(O(n2^{\frac{2}{3}n})\)
CF1552G - A Serious Referee (观察性质 - 只需对 01 序列满足 + 缩减状态 + 位运算)
注意到,"对任意 \(a_i\) 都能排序后都有序" 等价于 "对任意 \(01\) 序列排序后都有序":
-
左推右,显然
-
右推左,考虑对每个 \(x\),将 \(a_i\) 中的数根据其与 \(x\) 的大小关系赋为 \(0/1\)
若排序后 \(0/1\) 数列有序,则对于 \(x\) 这一分界线满足要求
若对任意 \(0/1\) 序列排序后都有序,则对任意 \(x\) 都满足要求,显然原数列有序
直接做是 \(O(n2^n)\) 的,考虑优化
注意到,我们每次无需重新枚举在之前的操作中已经枚举过了的位置
更进一步,对排序区间 \([l, r]\),只需知道 \([l, r]\) 中 \(0/1\) 的个数就能确定排序后结果;因此只需枚举不确定位置中 \(1\) 的个数
P.S. 用 long long 压缩状态,可以用位运算 \(O(1)\) 得到排序后结果:
-
预处理 \(T_i\) 表示第 \(i\) 次修改影响的位置集合,\(\text{pre}_i\) 表示前 \(i\) 次修改影响的位置集合
因此,第 \(i\) 次修改时确定位置为 \(T_i \land \text{pre}_{i-1}\)
-
预处理 \(l_{i, j}\) 强制使 \(S \land l_{i, j}\) 后第 \(i\) 次修改的前 \(j\) 个位置变成 \(0\),其余不变
转移形如 \(l_{i, j} = l_{i, j-1} \oplus (2^k-1)\),初始值为 \(l_{i, 0} = (2^n-1)\)
\(r_{i, j}\) 强制使 \(S \lor r_{i, j}\) 后第 \(i\) 次修改的后 \(j\) 个位置变成 \(1\),其余不变
转移形如 \(r_{i, j} = r_{i, j-1} \lor (2^k-1)\),初始值为 \(r_{i, 0} = 0\)
因此,设排序前所有位置中有 \(j\) 个 \(1\),排序后只需令 \(S \leftarrow S \land l_{i, q_i-j} \lor r_{i, j}\) 即可
分析时间复杂度:
- 设每轮不确定位置数为 \(a_1, a_2, \cdots, a_k\),显然有 \(\sum\limits_{i=1}^{k} a_i \le n\)
- 我们希望最大化 \(\prod\limits_{i=1}^{k} (a_i+1)\);由基础不等式,有 \(\prod\limits_{i=1}^{k} (a_i+1) \le (\frac{\sum\limits_{i=1}^{k} (a_i+1)}{k})^k \le (\frac{n+k}{k})^k\)
综上,时间复杂度 \(O((\frac{n+k}{k})^k)\)
10.5
模拟赛
非常不熟的期望 DP + 第 \(1\) 步就想错的 T3,你不输谁输?
10.5 T1 - 汤圆的世界 (大模拟)
考虑先把必须挖的都挖掉
显然,对剩下的每个连通块,我们贪心地希望留下的方块尽量多,这样更容易满足限制
因此直接对整个连通块 check 即可;由于 \(1\) 个方块最多满足 \(3\) 个限制,单次 check 复杂度就是 \(O(\text{siz})\) 的
时间复杂度 \(O(n^3)\)
10.5 T2 - 玻璃走廊 (期望 DP)
显然,最优策略就是每次贪心地开面前第 \(1\) 个门,不断尝试向前走
注意到还剩多少个门要开对操作有影响,考虑将其刻画到状态里
令 \(f_{i, j}\) 表示走到位置 \(i\ (0 \le i \le n)\),\(i+1 \sim n\) 中还有 \(j\) 个 1 (关着的门),走到终点的期望步数
注意到 0 的总数与 1 的总数是确定的,确定 \(i, j\) 后能算出前后各自 0 / 1 的数量,进而可知门 \(i+1\) 为 0/ 1 的概率 \(P_0\)
具体的,令 \(\text{suf}_i\) 表示原本 \(i+1 \sim n\) 中 1 的个数,\(\text{cnt}_0\) 表示 0 的总数,\(\text{cnt}_1\) 表示 1 的总数:
-
若门 \(i+1\) 本来就是
1,则 \(P_0 = 0\) -
反之,则 \(i+1 \sim n\) 中原有 \(c_0 = n-i-\text{suf}_i\) 个
0,需挑 \(c_1 = j-\text{suf}_i\) 个变成1因此,更改后门 \(i+1\) 仍为
0的概率为 \(P_0 = \frac{\binom{c_0-1}{c_1}}{\binom{c_0}{c_1}} = \frac{c_0-c_1}{c_0}\)
分讨转移情况:
-
门 \(i+1\) 为
0,转移为 \(f_{i, j} \leftarrow f_{i+1, j} \cdot P_0\) -
门 \(i+1\) 为
1:-
打开 \(i+1\) 后在前面关上;此时共有 \(\text{cnt}_0+1\) 个
0(包括新打开的 \(i+1\) ),前面有 \(i-(\text{cnt}_1-j)\) 个0因此,部分式子为 \(f_{i, j} \leftarrow (1+f_{i+1, j-1}) \cdot \frac{i-(\text{cnt}_1-j)}{\text{cnt}_0+1}\)
-
打开 \(i+1\) 后刚好又关上了;部分式子为 \(f_{i, j} \leftarrow (1+f_{i, j}) \cdot \frac{1}{\text{cnt}_0+1}\)
-
打开 \(i+1\) 后在后面关上;此时后面有 \(n-i-1-(j-1) = n-i-j\) 个
0(注意需舍掉 \(i+1\) )因此,部分式子为 \(f_{i, j} \leftarrow (1+f_{i+1, j}) \cdot \frac{n-i-j}{\text{cnt}_0+1}\)
综上,完整的递推式为 \(f_{i, j} = (1+f_{i+1, j-1}) \cdot \frac{i-(\text{cnt}_1-j)}{\text{cnt}_0+1} + (1+f_{i, j}) \cdot \frac{1}{\text{cnt}_0+1} + (1+f_{i+1, j}) \cdot \frac{n-i-j}{\text{cnt}_0+1}\)
移项可得 \(f_{i, j} = \frac{1}{\text{cnt}_0} \cdot ((1+f_{i+1, j-1}) \cdot (i-(\text{cnt}_1-j)) + 1 + (1+f_{i+1, j}) \cdot (n-i-j))\)
转移时还需要乘上外层概率 \(1-P_0\)
综上,为 \(f_{i, j} \leftarrow (1-P_0) \cdot \frac{1}{\text{cnt}_0} \cdot ((1+f_{i+1, j-1}) \cdot (i-(\text{cnt}_1-j)) + 1 + (1+f_{i+1, j}) \cdot (n-i-j))\)
-
初始值为 \(f_{n, i} = 0\),答案为 \(f_{0, \text{cnt}_1}\);实现上可以记忆化搜索,时间复杂度 \(O(n^2)\)
反思:期望 DP 需要加训!另外也别看到期望就害怕,还是可以尝试推一推的
10.5 T3 - 再见绘梨 (容斥 + DP)
看到 "出现次数 \(\ge 2\) ",首先考虑容斥
为什么要容斥?因为这样其他元素可以随意排,出现次数 \(\le 1\) 时也更容易统计
具体的,令 \(f_k\) 表示钦定 \(k\) 个元素只出现 \(\le 1\) 次,其他元素随便排的方案数
因此,答案为 \(\sum\limits_{i=0}^{n} (-1)^i \cdot \binom{n}{i} \cdot f_i \cdot 2^{2^{n-i}}\),后面的 \(2^{2^{n-i}}\) 表示由剩下 \(n-i\) 个元素挑一些组成的集合可以随便选
为方便推导,不妨令只出现 \(\le 1\) 的元素为 \(1, 2, \cdots, k\)
为刻画 \(1, 2, \cdots, k\) 的分配情况,再令 \(g_{i, j}\) 表示仅考虑 \(1, 2, \cdots, i\),将这 \(i\) 个数分配到 \(j\) 个集合中的方案数
因此,有 \(f_k \leftarrow \sum\limits_{i=0}^{k} g_{k, i} \cdot 2^{(n-k)i}\),后面的 \(2^{(n-k)i}\) 表示可将剩下 \(n-i\) 个数随意填充进集合中
对 \(g_{i, j}\) 的转移,考虑依次放入每个元素,有转移 \(g_{i, j} \leftarrow g_{i-1, j-1} + g_{i-1, j}(j+1)\) (新建集合 / 放入原有集合 / 扔掉当前元素)
初始值为 \(g_{i, 0} = 1\ (0 \le i \le n)\),即可以将所有元素全扔掉
时间复杂度 \(O(n^2 \log p)\),精细实现应该可以 \(O(n^2)\)
10.6
晚上打了 CF,又是战犯级挥发
10.5 T4 - 你、组乐队了吧 (正难则反 + 扫描线 + 线段树维护历史和)
同时维护两个条件是困难的,我们正难则反,考虑 \([l, r]\) 不合法的条件
显然,即为 \(\min\limits_{l \le x \le r} S_x \ne \min\limits_{l \le x \le r} M_x \lor \max\limits_{l \le x \le r} S_x \ne \max\limits_{l \le x \le r} M_x\);因此对 \(\min\) 和 \(\max\) 分别考虑即可
以 \(\min\) 为例,考虑固定 \(\min\) 值 \(v\),分析 \(S_i, M_i\) 各自区间的位置对答案的影响
令 \(\text{pos}_{1, v}, \text{pos}_{2, v}\) 表示值 \(v\) 在 \(S_i, T_i\) 中的下标,\([l_{1, v}, r_{1, v}], [l_{2, v}, r_{2, v}]\) 表示以 \(v\) 作为最小值的,\(S_i, T_i\) 中的极长连续段
\(l_{1, v}, r_{1, v}, l_{2, v}, r_{2, v}\) 容易通过单调栈预处理出来,这部分时间复杂度 \(O(n)\)
考虑将限制刻画到二维平面上
令 \(v\) 在 \(S_i\) 中对应所有 \((x, y)\ (x \in [l_{1, v}, \text{pos}_{1, v}],\ y \in [\text{pos}_{1, v}, r_{1, v}])\) 构成的矩形,在 \(T_i\) 中同理
显然,两矩形的交中的点满足 \(\min\) 的限制,其余点必不满足
考虑将两矩形中的点分别 \(+1\),交中的点 \(-2\),这样交中的点值为 \(0\),其余点均为 \(1\)
对 \(\min\) 与 \(\max\) 分别做如上操作,最终值为 \(0\) 的点对应的区间即为合法区间
对查询 \([l, r]\),即计数所有 \((x, y)\ (x \in [l, r],\ y \in [l, r])\) 中值为 \(0\) 的点的数量
综上,需要支持矩形加 + 矩形查值为 \(0\) 的点的数量
考虑扫描线
具体的,考虑从 \(y\) 轴下 \(\rightarrow\) 上扫,每次 \(y\) 坐标 \(+1\),维护 \(x\) 轴上的区间
套路地,对矩形加操作即 \(\text{add}((l, r, u, d), c)\),差分为 " \(d\) 时进行 \([l, r]+c\) " 与 " \(u+1\) 时进行 \([l, r]-c\) "
类似的,对查询操作即 \(\text{query}(l, r, u, d)\),差分为 " \(u\) 时查询 \([l, r]\) 的答案" \(-\) " \(d-1\) 时查询 \([l, r]\) 的答案"
维护值为 \(0\) 的点的个数是困难的;不过容易发现 \(0\) 必为最小值,于是只需维护最小值 + 最小值个数
注意,我们不可能在每次 \(y\) 坐标 \(+1\) 时都对矩形对应的 \(x\) 轴区间做区间加;因此,需维护 \(x\) 轴区间的最小值个数的贡献次数
换句话说,就是维护区间内值为 \(0\) 的点的个数的历史和
综上,需要维护区间 \(\min\) ( \(\text{seg}\) ) + 区间 \(\min\) 出现次数 ( \(\text{cnt}\) ) + 历史和 ( \(\text{sum}\) ),支持区间加
考虑维护加法 tag ( \(\text{laz}\) ),对历史和再维护贡献次数 tag ( \(t\) )
实现细节:
-
pushup:正常 pushup 即可 -
pushdown:对 \(t\),若当前区间 \(\min\) 与子区间 \(\min\) 相等,则下传;反之不下传P.S. 下传即 \(t' \leftarrow t'+t\) 且 \(\text{sum}' \leftarrow \text{sum}' + \text{cnt}' \cdot t\)
对其他 tag 正常 pushdown 即可
-
update,get等正常做即可 -
在 \(y\) 坐标 \(+1\) 后:
-
首先,完成当前 \(y\) 坐标对应的区间加操作
-
若全局 \(\text{seg}_{\text{root}}\) 为 \(0\),令 \(t_{\text{root}} \leftarrow t_{\text{root}}+1\),且 \(\text{sum}_{\text{root}} \leftarrow \text{sum}_{\text{root}}+\text{cnt}_{\text{root}}\)
反之,说明没有值为 \(0\) 的点,无需更新覆盖次数与历史和
-
最后,完成当前 \(y\) 坐标对应的查询操作即可
-
时间复杂度 \(O(n \log n)\)
CF2045E - Narrower Passageway (期望转计数 + 拆式子 + 拆贡献)
显然,我们只需求出每种可能情况的贡献之和,最后除以 \(2^n\) 即可
考虑将式子拆为 \(m_1+m_2-m_1[m_1 = \max(m_1, m_2)]-m_2[m_2 = \max(m_1, m_2)]\)
对于前两项,以 \(+m_1\) 为例,拆贡献,枚举第 \(1\) 行中的每个位置 \(i\):
-
单调栈 / 二分 + ST 表求出极长连续段 \([l, r]\),满足 \(\max\limits_{l \le k \le i} P_{1, k} = P_{1, i}\ \land\ \max\limits_{i+1 \le k \le r} P_{1, k} < P_{1, i}\)
-
贡献即为 \(\sum\limits_{l'=l}^{i} \sum\limits_{r'=i}^{r} 2^{l'-2} \cdot 2^{n-r'-1} = (2^{i-1}-2^{l-2})(2^{n-i}-2^{n-r-1})\)
P.S. 对 \(l=1\) 或 \(r=n\) 的情况,可假装 \(2^{-1} = 0\)
对于后两项,以 \(-m_1[m_1 = \max(m_1, m_2)]\) 为例,仍然枚举第 \(1\) 行中的位置 \(i\)
此时极长连续段 \([l, r]\) 只需再满足一个 \(\max\limits_{l \le k \le r}P_{2, k} \le P_{1, i}\) 的限制即可
时间复杂度 \(O(n \log n)\) 或 \(O(n)\)
P11674 [USACO25JAN] Reachable Pairs G (时光倒流 + 刻画操作 + 并查集)
删点不好做,考虑时光倒流变成加点
设第 \(i\) 个连通块的大小为 \(\text{siz}_i\),容易发现答案即为 \(\sum \frac{\text{siz}_i \cdot (\text{siz}_i-1)}{2}\)
对操作 \(1\),遍历点 \(u\) 的每个出边 \((u, v)\),若 \(v\) 已存在就用合并 \(u, v\) 所在连通块 + 更新答案
对操作 \(2\),容易发现对连通性没有影响,只造成连通块 \(\text{siz} \leftarrow \text{siz}+1\),更新 \(\text{siz}\) 与答案即可
注意,初始时操作 \(2\) 对应的点应视为 "已存在",只不过 \(\text{siz} = 0\)
P12028 [USACO25OPEN] Moo Decomposition G (观察性质)
注意到 "重复 \(L\) 次拼接" 是假的,不可能有 MOO...O 跨过连接处
证明:反证,考虑第 \(1\) 个串,若存在 MOO...O 跨过连接处则必然有 O 匹配不上 M,这个 O 即不合法;归纳易证
考虑如何求 \(S\) 的划分方案数
考虑由限制严到限制松,即从后向前匹配
维护当前 O 的个数 \(\text{cnt}\) 与答案 \(\text{ans}\):
- 若 \(s_i\) 为
O,则 \(\text{cnt} \leftarrow \text{cnt}+1\) - 若 \(s_i\) 为
M,则 \(\text{ans} \leftarrow \text{ans} \cdot \binom{\text{cnt}}{K}\),且 \(\text{cnt} \leftarrow \text{cnt}-K\)
最终答案即为 \(\text{ans}^L\)
CF2145A - Candies for Nephews (模拟)
CF2145B - Deck of Cards (观察性质)
CF2145C - Monocarp's String (赋权 + 限制前缀和 + map)
10.7
P11842 [USACO25FEB] Bessie's Function G (刻画限制 + 基环树 DP)
连边 \(i \rightarrow a_i\),限制转化为 \(i\) 本身是自环 / \(i\) 连向一个自环
容易发现,若选择改变 \(a_i\),必然将 \(a_i\) 改成 \(i\) (即改成自环)
综上,对于每条原本的边 \((u, v)\),要求改动后 \(u, v\) 中至少 \(1\) 个是自环
容易发现这个限制与边的方向性无关,为方便 DP,可将所有有向边改成无向边
原图是一个基环树;考虑断环,再钦定断边两端点至少 \(1\) 个必选
令 \(f_{u, 0/1}\) 表示点 \(u\) 不改 / 改,子树内最小代价
转移显然为 \(f_{u, 0} \leftarrow \sum f_{v, 1}\) 与 \(f_{u, 1} \leftarrow c_u+\sum \min(f_{v, 0}, f_{v, 1})\)
初始值为 \(f_{\text{leaf}, 0} = 0, f_{\text{leaf}, 1} = c_i\)
为实现方便,可分别强制断边端点为根,答案即为 \(f_{\text{root}, 1}\) (强制必选)
时间复杂度 \(O(n)\)
P12029 [USACO25OPEN] Election Queries G (刻画限制 + 双指针 + set + 观察性质)
设 \(c_i\) 表示 \(i\) 收到的票数,容易发现 \(i, j\ (i \ne j)\) 能成为领头牛的充要条件是 \(c_i+c_j \ge \max\limits_{1 \le k \le n} c_k\)
考虑 \(q = 1\) 怎么做
维护 \(l_v, r_v\) 表示满足 \(c_i = v\) 的 \(i\) 的最小值 / 最大值
设 \(\text{mx} = \max\limits_{1 \le k \le n} c_k\),枚举 \(c_i = v\ (1 \le v \le n)\),则要求 \(c_j \ge \max(1, \text{mx}-v)\)
容易发现 \(v\) 增大时 \(\text{mx}-v\) 减小,令左端点为 \(l_v\),双指针维护最大右端点即可
将这个做法直接重复 \(q\) 次是 \(O(qn)\) 的
注意到 \(\sum c_i = n\),本质不同的 \(c_i\) 只有 \(\sqrt{n}\) 个
只枚举满足 \(c_i > 0\) 的 \(c_i\),时间复杂度为 \(O(q \sqrt n)\)
所有信息均可用 set 维护,总时间复杂度 \(O(n \log n + q \sqrt n)\)
P11673 [USACO25JAN] Median Heap G (树形 DP + 观察性质 - 修改次数不超过 2)
考虑 \(q = 1\) 怎么做
直接的想法是令 \(f_{i, j}\) 表示操作完 \(i\) 子树,\(i\) 上填 \(j\) 的最小代价
问题是值域高达 \(10^9\),显然无法接受
注意到无需维护具体的数,只需维护与 \(m\) 的大小关系即可
令 \(f_{i, 0/1/2}\) 表示操作完 \(i\) 子树,\(i\) 上填的数小于 / 等于 / 大于 \(m\) 的最小代价
转移为 \(f_{u, \text{mid}(a, b, c)} \leftarrow f_{v_1, a}+f_{v_2, b}+w(u, c)\),其中 \(w(u, c)\) 表示将 \(a_u\) 变成对应状态的最小代价
初始值为 \(f_{\text{leaf}, c} = w(\text{leaf}, c)\),答案为 \(f_{1, 1}\),单次时间复杂度 \(O(n)\)
直接做 \(q\) 次是 \(O(nq)\) 的,无法接受
注意到 \(w(u, i)\) 最多被修改两次 ( \(m_i < a_u \land m_{i+1} \ge a_u\) 或 \(m_i = a_u \land m_{i+1} > a_u\) 时)
将询问离线,按 \(m_i\) 从小到大排序;由于树高为 \(O(\log n)\),每次将修改的点的到根链拉出来,暴力跳父亲更新 DP 值就是对的
时间复杂度 \(O(n \log n)\)
10.8
模拟赛,但真的是 NOIP 模拟赛 (?
10.8 T1 - 乘积 (随机化性质 - 区间长度大于阈值时大概率合法 + 双指针)
20 pts:
考虑将 \(a_{t_1} \cdot a_{t_2} \cdot a_{t_3} \cdot a_{t_4} \equiv k\ (\bmod P)\) 对半分,转化为 \(a_{t_1} \cdot a_{t_2} \equiv \text{inv}(a_{t_3}) \cdot \text{inv}(a_{t_4}) \cdot k\ (\bmod P)\)
对每个询问 \(l, r\),枚举子区间,开桶维护 \(a_{t_1} \cdot a_{t_2}\ (\bmod P)\),查询 \(\text{inv}(a_{t_3}) \cdot \text{inv}(a_{t_4}) \cdot k\ (\bmod P)\) 是否出现过即可
时间复杂度 \(O(qn^2)\)
30 pts / 100 pts:
考虑怎么把复杂度里的 \(q\) 去掉
显然答案有单调性,对于每个 \(l\),求出最小的 \(r\) 使得 \([l, r]\) 合法即可
考虑双指针:
-
当 \(r' \leftarrow r+1\) 时,枚举 \(l \le i \le r'\),将 \(a_i \cdot a_r\ (\bmod P)\) 加入桶
此时若状态从不合法变为合法,必有 \(t_4 = r\)
枚举 \(t_3\),查询 \(\text{inv}(a_{t_3}) \cdot \text{inv}(a_{t_4}) \cdot k\ (\bmod P)\) 即可
-
当 \(l' \leftarrow l+1\) 时,枚举 \(l \le i \le r\),将 \(a_l \cdot a_i\ (\bmod P)\) 扔出桶
此时若状态从合法变为不合法,必有 \(t_1' = l\)
于是在移动 \(r\) 之前,先扫一遍判下即可
时间复杂度 \(O(n^2 + q)\)
注意到 \(a_i\) 随机,期望合法区间长度为 \(\sqrt[4]{P}\)
因此,我们总共扫过的距离不会很长,可以通过
时间复杂度 \(O(n \sqrt[4]{p})\)
反思:多观察单调性等信息,考虑预处理;数据随机时,考虑合法条件限制会较松 / 较严,一般与某个阈值有关
10.8 T2 - 简单环 (观察性质 + 贪心)
打表容易发现,\(x = x_0\) 时的答案等于 \(x = 1\) 时的答案乘 \(x_0\)
事实上这是符合直觉的;考虑将操作刻画为选择两点,起点 \(-1\),终点 \(+1\),代价为边权和
我们肯定希望按代价从大到小考虑,每次都操作到不能操作为止
考虑观察性质:
-
"以 \(u\) 为起点到 \(v\) " 等价于 "以 \(v\) 为起点到 \(u\) ",因为边权和为相反数
一个点不能均作为起点 / 终点被操作两次,由贪心方案易知
-
一个点不能既作为起点也作为终点被多次操作,因为这样不如将两次操作合并
若两次操作合并后不优,说明这两次操作本身就不优
综上,一个点实际只会被操作一次
将 "代价为边权和" 转化为 "边权前缀和之差",问题即转化为对前缀和两两配对,使差的绝对值之和最大
由经典贪心,对前缀和排序后 \((1, n), (2, n-1), \cdots\) 配对即可
时间复杂度 \(O(n+q)\)
10.9
10.8 T3 - 追忆 (转化限制 - 求导刻画单调性 + 数位 DP 套 01 DP 优化完全背包)
先推推式子转化限制:
考虑定义 \(f(x) = \sum\limits_{i=1}^{n} \sum\limits_{j=1}^{n} \frac{a_i \cdot a_j}{c_i+c_j} x^{c_i+c_j}\),则原式为 \(f(1)+f(\frac{2}{3})+f(\frac{1}{3})\)
注意到分母上的 \(c_i+c_j\) 很烦,我们希望把它去掉,这样就能把 \(i, j\) 分离出来
注意到这与求导的性质相契合;这启示我们求导刻画函数的单调性:
当 \(x > 0\) 时,\(f'(x) \ge 0\),因此有 \(f(x)\) 单调不降
注意到 \(f(0) = 0\),又因为 \(f(1)+f(\frac{2}{3})+f(\frac{1}{3}) = 0\),必然有 \(f(1) = 0, f(\frac{2}{3}) = 0, f(\frac{1}{3}) = 0\)
由此,可以得出 \(\forall x \in [0, 1],\ f'(x) = 0\);也就是说,对所有 \(v\),我们都有 \(\sum\limits_i [c_i = v]\ a_i = 0\)
显然对不同的 \(c_i = v\),限制条件是相同的;以下默认在所有 \(c_i\) 均相同的情况下考虑
整理下限制,为:
注意到 \(-\sum\limits_{i=1}^{n} s_i\) 为定值,问题转化为完全背包,求刚好装到某个容量的方案数
由于 \(n \le 15,\ d_i \le 20,\ \sum\limits_{i=1}^{n} s_i \le 15 \cdot 10^{9}\),这其实是个特化的完全背包问题 (例题:CF1290F - Making Shapes )
这类问题的特点是物品数很小,容量很小,要装到的目标容量很大
对于这类问题,我们考虑在数位上做,每次确定所有 \(t_i\ (1 \le i \le n)\) 在当前位上的选择 ( \(0/1\) ),维护进位 + 与 \(s_i\) 的大小关系
具体的,令 \(f_{i, j, 0/1/2}\) 表示从低向高填到第 \(i\) 位,向后的进位为 \(j\),当前与 \(s_i\) 的低 \(i\) 位的大小关系为 \(<\) / \(=\) / \(>\) 的方案数
为什么从低到高?因为我们要维护进位,从低向高的进位不会影响低位的选择
考虑转移:
-
朴素转移为暴力 \(2^n\) 枚举所有 \(t_i\) 当前位上填的 \(x_i\ (x_i \in \{0, 1\})\),则新产生的进位量为 \(k = \sum\limits_{i=1}^{n} [x_i = 1] t_i\)
转移大概为 \(f_{i, j, 0/1/2} \rightarrow f_{i+1, \lfloor \frac{j+k}{2} \rfloor, 0/1/2}\) (对第三维,认为 \(i+1\) 位填 \((j+k) \land 1\),比较与 \(s_{i+1}\) 的大小关系即可)
记 \(B = \log (\sum\limits_{i=1}^{n} s_i),\ D = \sum\limits_{i=1}^{n} d_i\),时间复杂度为 \(O(2^nqnDB)\)
-
注意到确定 \(k = \sum\limits_{i=1}^{n} [x_i = 1] t_i\) 的过程实际上是 01 背包,考虑把 \(2^n\) 枚举的过程改成 01 背包
令 \(g_{i, j}\) 表示对前 \(i\) 个物品做 01 背包,装出 \(j\) 的方案数;容易在 \(O(D)\) 的时间复杂度内求出 \(g_{i, j}\)
预处理 \(g_{i, j}\),转移时枚举装到的容量 \(j\),时间复杂度为 \(O(qD^2B)\)
注意到没必要枚举两次 \(D\),可将之前的 DP 值作为 01 背包的初值,每次转移都跑一遍 01 背包
具体的,原本的初值为 \(g_{0, 0} = 1\),此时我们修改初值为 \(g_{0, j} = f_{i, j, 0/1/2}\),将初始的进位直接刻画到背包中
时间复杂度 \(O(qnDB)\)
-
考虑如何把时间复杂度里的 \(q\) 优化掉
注意到修改改变的只有 \(\sum\limits_{i=1}^{n} s_i\),考虑把填成的状态 \(S\) 记到 DP 里
但 \(S\) 多达 \(2^{34}\),存不下;考虑折半,记 \(B' = 17\),只存 \(B'\) 位 \(S\)
注意到影响后 \(B'\) 位 \(S\) 转移的只有前 \(B'\) 位向后 \(B'\) 位的进位,于是查询时 \(O(D)\) 枚举进位即可
实现上,无需每次枚举进位后重新 DP,设进位为 \(x\),则后 \(B'\) 位要填出的值即为 \((S\text{>>}17)-x\),直接查即可
修改定义,令 \(f_{S, i, j}\) 表示前 \(i\) 位填出 \(S\),进位为 \(j\) 的方案数
类似的,转移为 \(f_{S, i, j} \rightarrow f_{S \lor [(j +k) \land 1] 2^i, i+1, \lfloor \frac{j+k}{2} \rfloor}\),\(k\) 为 01 背包求出的新进位
时间复杂度 \(O(2^{B'}nD+qD)\),可以通过
综上,时间复杂度 \(O(2^{B'}nD+qD)\)
10.12
P11843 [USACO25FEB] The Best Subsequence G (二分 + 分讨)
考虑先把修改变成互不相交的区间
对修改位置离散化 + 差分,将修改 \([l, r]\) 变成 \(a_l \leftarrow a_l \oplus 1\),\(a_{r+1} \leftarrow a_{r+1} \oplus 1\)
对离散化后的极长 \(1\) 连续段 \([l', r']\),其代表原区间 \([v_{l'}, v_{r'+1}-1]\) 为 \(1\)
对查询 \([l, r]\),答案必为对最靠后的合法的 \(\text{pos}\),选择 \([l, \text{pos}]\) 中所有的 \(1\) 与后缀 \([\text{pos}+1, r]\)
先二分 \(\text{pos}\) 在哪个 \(1\) 连续段后,大力分讨,算出其在 \(0\) 连续段中的具体位置,最后计算答案
时间复杂度 \(O(n \log n)\)
细节一大堆,特别不好调……
10.13
P12031 [USACO25OPEN] Forklift Certified P (线段树 + dfs 求拓扑序)
对 \(M=2\) :
显然,箱子 \(i\) 阻碍箱子 \(j\) 移走等价于箱子 \(i\) 的左下角在箱子 \(j\) 的右上角框出的矩形中
对所有箱子 \(i\) 按 \(x_{i1}\) 排序,对 \(y_{i1}\) 建线段树,维护区间 \(\text{min}\)
查询 \(i\) 时,二分比 \(x_{i2}\) 小的第 \(1\) 个位置,查询前缀 \(\min\),判断是否 \(\ge y_{i2}\) 即可
删除箱子即为将对应的 \(y_{i1}\) 置为 \(+\infty\)
细节上,注意可能有自环,因此查询前需先将自身对应的 \(y_{i1}\) 置 \(+\infty\)
时间复杂度 \(O(n \log n)\)
对 \(M=1\) :
注意到,问题等价于对冲突的箱子对连有向边,求一组拓扑排序
考虑 dfs 求拓扑排序,依次尝试每个箱子:
- 若没有箱子与其冲突,移走当前箱子
- 如存在箱子与其冲突,dfs 这个箱子并把它移走;反复执行直到没有箱子与当前箱子冲突
按 \(M=2\) 的方式用线段树维护即可
容易发现每个点只会被删一次,时间复杂度 \(O(n \log n)\)
P11676 [USACO25JAN] DFS Order P (树形区间 DP + dfs 树性质)
考虑在 dfs 树上考虑
注意到,若 dfs 序为 \(1, 2, \cdots, n\),dfs 树的每个子树对应的 dfs 序必为连续区间,且根必为最小点
这启示我们每个子树是相同的子问题,考虑树形区间 DP
令 \(f_{l, r}\) 表示构造以 \(l\) 为根,dfs 序为 \([l, r]\) 的 dfs 树的最小代价
转移为 \(f_{l, r} \leftarrow f_{l, k} + f_{k+1, r} + \max(0, a_{l, k+1})\)
但这是不对的,因为我们没有考虑横叉边的影响
考虑修改定义为 \(f_{l, r}\) 表示构造以 \(l\) 为根,dfs 序为 \([l, r]\),且没有向 \(r+1 \sim n\) 的横叉边的 dfs 树的最小代价
则转移为 \(f_{l, r} \leftarrow \min(f_{l, k} + f_{k+1, r} + \max(0, a_{l, k+1}))+\sum\limits_{i=r+1}^{n} \max(0, -a_{l, i})\)
预处理后缀和,时间复杂度 \(O(n^3)\)
细节上,注意转移时将 \(l\) 为左端点的区间转移完再补上 \(\sum\limits_{i=r+1}^{n} \max(0, -a_{l, i})\),避免重复计算后面横叉边的代价
P11844 [USACO25FEB] Friendship Editing G (补图 + 状压 DP)
考虑原命题的逆否命题
即将 "若存在边 \((a, b)\),则必然存在 \((a, c)\) 或 \((b, c)\) " 转化为 "若不存在 \((a, c)\) 与 \((b, c)\),则不存在 \((a, b)\) "
这启示我们在补图上考虑,转化为 "若存在 \((a, c)\) 与 \((b, c)\),则存在 \((a, b)\) "
容易发现,补图是许多点集不交的完全图的并
直接在补图上 DP,令 \(f_{S}\) 表示使 \(S\) 中的点符合要求的最小代价
预处理 \(g_{S}\) 表示使 \(S\) 中的点连成完全图的最小代价,\(h_{u, S}\) 表示去掉 \(u\) 与 \(S\) 间的所有连边的最小代价
转移即为 \(f_{S} \leftarrow f_{T} + g_{S/T} + \sum\limits_{u \in S/T} h_{u, T}\)
直接做时间复杂度是 \(O(3^nn+2^nn^2)\) 的
注意到瓶颈在于 \(\sum\limits_{u \in S/T} h_{u, T}\),考虑把 \(T\) 带来的影响去掉,直接去掉 \(S/T\) 中的点与其他所有点的连边
这样相当于强制每条边拆 \(2\) 次,同时把 \(g_S\) 中加一条边的代价改成 \(2\),最后答案除以 \(2\) 即可
初始值为 \(f_{S} = +\infty, f_0 = 0\),答案为 \(f_{2^n-1}\)
时间复杂度 \(O(3^n + 2^nn^2)\)
10.14
P11847 [USACO25FEB] True or False Test P (观察性质 + 贪心 + 类决策单调性分治)
考虑先让 Bessie 选若干道题目获得 \(\sum a_i\) 的得分,再让 Elsie 选 \(k\) 道减去 \(\sum (a_i + b_i)\)
容易发现,按 \(a_i+b_i\) 从大到小排序,Elsie 必然会扣掉 Bessie 选的前 \(k\) 道题
P.S. 临项交换同样能够导出这一结论
枚举分界点 \(i\),则 Bessie 希望贪心地在 \([1, i]\) 中选 \(k\) 个使得 \(\sum b_j\) 最小,\([i+1, n]\) 全选,最大化 \(\sum\limits_{j > i} a_j - \min \sum b_j\)
注意到 \(k \rightarrow k+1\) 时,最优决策点不会左移:
- 若左移,设原决策点为 \(i_1\),现决策点为 \(i_2\),当前方案中必有至少 \(1\) 个 \(j \in [1, i_2]\) 使得 \(j\) 在 \([1, i_1]\) 中未选
- 容易发现,不改变其他选择,直接在 \(k\) 时的决策中选上 \(j\) 必然比当前更优
那么类似决策单调性优化 DP,分治解决即可
实现上可以上主席树维护 \(\min \sum b_j\)
时间复杂度 \(O(n \log^2 n)\)
10.15
P11845 [USACO25FEB] Min Max Subarrays P (打表找规律 + 分讨 + 容斥)
打表发现,\(\text{len} \ge 7\) 且 \(\text{len}\) 为奇数时答案必为最大值,\(\text{len} \ge 8\) 且 \(\text{len}\) 为偶数时答案必为次大值
对每个点,维护 \(\text{ls}_i, l_i, r_i, \text{rs}_i\) 表示左 / 右第 \(1\) / \(2\) 个大于当前数的数的位置
枚举 \(i\),拆贡献:
-
\(i\) 为最大值的贡献为选择 \(l \in [l_i, i], r \in [i, r_i]\),满足 \(r-l+1\) 为奇数的方案数
\(\text{len} \ge 7\) 的选择方案可以直接容斥掉;最后别忘了乘 \(a_i\)
-
\(i\) 为次大值的贡献为选择 \(l \in (\text{ls}_i, l_i], r \in [i, r_i)\) 或 \(l \in (l_i, i], r \in [r_i, \text{rs}_i)\),满足 \(r-l+1\) 为偶数的方案数
同理,对 \(\text{len} \ge 8\) 容斥,最后乘 \(a_i\)
对 \(n \le 6\) 的部分,枚举排列,记忆化暴搜即可
时间复杂度 \(O(n \log n)\)
P12032 [USACO25OPEN] Lazy Sort P (观察性质 + 划分连续段 + 组合数学)
打表发现,序列合法的充要条件是不存在逆序对 \((i, j)\),使得 \(i < j\) 且 \(a_i-a_j \ge 2\)
考虑将满足 \(\forall i \in [l, r],\ a_i = a_l \lor a_i = a_l-1\) 的极长连续段 \([l, r]\) 划分出来
我们称 \(a_l\) 为连续段 \([l, r]\) 的标志值,容易发现 \(a_l\) 单增
一种想法是 DP,将 \(a_l\) 记到状态里,容易做到 \(O(nV^2)\);不过这是没有前途的
考虑 \(q = 2\) 怎么做
令 \(\text{calc}(\text{len}, x, y)\) 表示长为 \(\text{len}\),首位所在连续段的标志值为 \(x\),末位所在连续段的标志值为 \(y\),中间的填法数
考虑如何求 \(\text{calc}(\text{len}, x, y)\):
-
先判掉 corner case:
- 若 \(x > y\),方案数为 \(0\)
- 若 \(\text{len} = 1\),方案数为 \([x = y]\)
- 若 \(x = y\),方案数为 \(2^{\text{len}-1}\) (首位必填 \(x\),后面随便填)
-
枚举 \(c\ (2 \le c \le \min(y-x+1, \text{len}))\),表示我们要将其划为 \(c\) 段
-
考虑分配断点,贡献为 \(\binom{\text{len}-1}{c-1}\)
-
考虑分配段标志值,贡献为 \(\binom{y-x+1}{c-2}\) (首尾已确定)
-
对每段,设标志值为 \(v_i\),长度为 \(l_i\),首位必填 \(v\),其余位置有填 \(v\) 与 \(v-1\) 两种方案
因此,贡献为 \(2^{\sum (l_i-1)} = 2^{\text{len}-c}\)
-
综上,总方案数为 \(\sum\limits_{2 \le c \le \min(y-x+1, \text{len})} \binom{\text{len}-1}{c-1} \cdot \binom{y-x+1}{c-2} \cdot 2^{\text{len}-c}\)
P.S. 实现上,注意到组合数连续,每次求新的组合数时上下补乘一位即可
考虑推广到原问题
令 \(f_{i, 0/1}\) 表示考虑到第 \(i\) 个关键点,当前标志值为 \(v_i\) / \(v_i+1\) 的方案数
转移为:
-
记 \(\text{len} = c_{i}-c_{i-1}+1,\ x = v_{i-1},\ y = v_i\)
-
从 \(f_{i-1, 0}\) 转移至 \(f_{i, 0}\) 时,系数为 \(x_{00} = \text{calc}(\text{len}, x, y)-\text{calc}(\text{len}-1, x, y)\)
后面减去的部分代表去掉末位填 \(v_{i}-1\) 而非 \(v_i\) 的贡献
-
从 \(f_{i-1, 0}\) 转移至 \(f_{i, 1}\) 时,系数为 \(x_{01} = \text{calc}(\text{len}-1, x, y+1)\)
\(\text{len}-1\) 代表强制末位填 \(v_i\)
-
从 \(f_{i-1, 1}\) 转移至 \(f_{i, 0}\) 时,系数为 \(x_{10} = \text{calc}(\text{len}, x+1, y)-\text{calc}(\text{len}-1, x+1, y)\),原因同上
-
从 \(f_{i-1, 1}\) 转移至 \(f_{i, 1}\) 时,系数为 \(x_{11} = \text{calc}(\text{len}-1, x+1, y+1)\),原因同上
-
综上,有转移:
- \(f_{i, 0} \leftarrow x_{00} \cdot f_{i-1, 0} + x_{10} \cdot f_{i-1, 1}\)
- \(f_{i, 1} \leftarrow x_{01} \cdot f_{i-1, 0} + x_{11} \cdot f_{i-1, 1}\)
初始值为 \(f_{0, 0} = 1, f_{0, 1} = 0\);答案为 \(f_{q, 0} + f_{q, 1}\)
时间复杂度 \(O(n)\)
10.16
P12030 [USACO25OPEN] OohMoo Milk G (贪心 + 拆分过程 + 二分)
贪心地,由于使较大的 \(m_i\) 加 \(1\) 对现在及以后的答案增量影响更大:
- John 必然选择使前 \(A\) 大的 \(m_i\) 加 \(1\)
- Nhoj 必然选择使前 \(B\) 大的 \(m_i\) 减 \(1\)
按初始 \(m_i\) 从大到小排序,容易发现只有前 \(A\) 个会被操作到,后面的可以扔掉
Nhoj 每次选择的位置可能变化,我们不好维护;但注意到 John 每次必然执行全局加,于是考虑将加和减的过程拆分
具体的,先对所有 \(1 \le i \le A\) 执行 \(m_i \leftarrow m_i+D\),再让 Nhoj 选择一些位置减少:
- 设 Nhoj 让 \(m_i\) 减少了 \(c_i\),显然有 \(c_i \le D\)
- 同时,还要满足 \(\sum c_i = B \cdot D\)
考虑将所有 \(m_i\) 按在最终方案中减完 / 没减完 \(D\) 次分类:
- 考虑二分 \(\text{mid}\),代表所有没减完 \(D\) 次的 \(m_i\) 中,减完后剩余容量的最大值
- 考虑如何 check:
-
若 \(m_i-D \ge \text{mid}\),直接减完 \(D\),令代价 \(w \leftarrow w+D\)
-
反之,令 \(w \leftarrow w+m_i-\text{mid}\)
-
若 \(w > B \cdot D\),说明不合法
-
反之合法,从大到小考虑每个没减完 \(D\) 次的 \(m_i\) 并将其改为 \(m_i-1\),直到剩余次数用完为止
P.S. 改到 \(m_i-2\) 及以下的方案会在 \(\text{mid}\) 更小时考虑到
-
时间复杂度 \(O(n \log V)\)
10.17
想 P11678 [USACO25JAN] Watering the Plants P
10.18
P11678 [USACO25JAN] Watering the Plants P (slope trick + 平衡树)
首先,容易得到 \(O(nV^2)\) 的 DP 做法
令 \(f_{i, j}\) 表示使用前 \(i-1\) 条水渠,前 \(i-1\) 个植物满足要求,且第 \(i\) 个植物水量为 \(j\) 的最小代价
转移显然有 \(f_{i, j} \leftarrow \min\limits_{k \ge \max(w_{i-1}-j, 0)} f_{i-1, k} + c_{i-1} \cdot j\)
初始值为 \(f_{1, 0} = 0\),其余为 \(+\infty\);询问 \(i\) 的答案为 \(\min\limits_{j \ge w_i} f_{i, j}\)
维护后缀 \(\min\) 可以优化到 \(O(nV)\)
我们大胆猜测当 \(i\) 不变时,\(f_{i, j}\) 是凸的
证明如下:
- 注意到当 \(i \leftarrow i+1\) 时,我们实际上干的事是:
- 取后缀 \(\min\)
- 将 \([0, w_{i-1}]\) 翻转
- 将 \((w_{i-1}, V]\) 推平为全局 \(\min\)
- 累加上斜率为 \(c_{i-1}\) 的一次函数
- \(i = 1\) 时,\(f_{i, 0} = 0\),其余为 \(+\infty\)
- \(i = 2\) 时,\([0, w_1)\) 为 \(+\infty\),\([w_1, V]\) 为起点在 \((w_1, c_1w_1)\),斜率为 \(c_1\) 的一次函数
- \(i = 3\) 时,分类讨论:
-
取后缀 \(\min\) 相当于将 \([0, w_1)\) 推平成 \(c_1w_1\),\([w_1, V]\) 不变
-
若 \(w_2 \le w_1\):
- 翻转相当于啥也没干
- \((w_2, V]\) 会被推平成 \(c_1w_1\)
- 最终即在水平线 \(y = c_1w_1\) 上累加一次函数
综上,会形成起点在 \((0, c_1w_1)\),斜率为 \(c_2\) 的一次函数
-
若 \(w_2 > w_1\):
-
原本
\([0, w_1)\) 为水平线 \(y = c_1w_1\),\([w_1, w_2]\) 内为起点在 \((w_1, c_1w_1)\),斜率为 \(c_1\) 的一次函数 -
翻转后 \([0, w_2-w_1]\) 为起点在 \((0, c_1w_2)\),斜率为 \(-c_1\) 的一次函数
\((w_2-w_1, w_2]\) 为水平线 \(y = c_1w_1\)
-
\((w_2, V]\) 会被推平为 \(c_1w_1\)
-
最终再累加一次函数
综上,\([0, w_2-w_1]\) 为起点在 \((0, c_1w_2)\),斜率为 \(c_2-c_1\) 的一次函数
\((w_2-w_1, V]\) 为起点在 \((w_2-w_1, c_1w_1+c_2(w_2-w_1))\),斜率为 \(c_2\) 的一次函数
-
-
综上,不难发现 \(i = 3\) 时函数必定是下凸的
-
- \(i > 3\) 时,令 \(f_{i-1, j}\) 中第一个最小值点的 \(x\) 坐标为 \(\text{mn}\),分类讨论:
-
取后缀 \(\min\) 相当于将 \([0, \text{mn}]\) 推平成原最小值,\((\text{mn}, V]\) 不变
-
若 \(w_{i-1} \le \text{mn}\):
- 翻转相当于啥也没干
- \((\text{mn}, V]\) 会被推平为原最小值
- 最终即在水平线上累加一次函数
综上,此时退化为一次函数,仍是下凸的
-
若 \(w_{i-1} > \text{mn}\):
- 翻转相当于将 \([\text{mn}, w_{i-1}]\) 翻转并移到最前面
- \((\text{mn}, V]\) 会被推平为原最小值
- 最终再累加一次函数
发现累加一次函数很烦,我们考虑在差分 (斜率) 序列上分析,变为全局斜率加
由于 \(f_{i-1. j}\) 下凸,原 \((\text{mn}, w_{i-1}]\) 的斜率恒正且不降,翻转并取反后恒负且不降
由于这段被移动到了最前面,此时斜率序列应先恒负且不降,后面全是 \(0\);整体是单调不降的
最终全局加不影响凹凸性
因此,我们能够证得当前函数仍下凸
-
综上,\(f_{i, j}\) 仍是下凸的
-
通过上述证明,我们发现 \(i > 3\) 时 \(f_{i, j}\) 是下凸的;\(i \le 3\) 时暴力 DP 即可
考虑直接用平衡树按照证明过程维护差分序列,需要支持:
- 区间翻转并取反
- 将区间移到最前面
- 区间推平为 \(0\)
- 全局加
- 查询区间和
FHQ-Treap 维护即可,实现上需要维护翻转并取反 tag,推平 tag,加法 tag 共三个 tag
由证明,差分序列单调不降,且必为负 $\rightarrow 0 \rightarrow $ 正的形式 (当然也可能恒非负)
因此,可以直接对 \(0\) 按值分裂求出第一个最小值点的位置
实现时需要手动查询全局 \(\min\) 维护 \(f_{i, 0}\)
时间复杂度 \(O(n \log V + V)\)
10.21
P11846 [USACO25FEB] Transforming Pairs P (观察性质 + 分类讨论)
P.S. 为方便分析,以下令 \((a, b), (c, d)\) 为平面直角坐标系中的点
先考虑 \(a, b, c, d \ge 0\) 怎么做
注意到由 \((c, d)\) 倒推的过程是确定的,即为辗转相除
在平面直角坐标系上,辗转相除即为 \((c, d) \rightarrow (x', 0) / (0, y')\) 的过程,\(x > y\) 时向左走,反之向下走
模拟行走过程,对每条横线 / 竖线判断 \((a, b)\) 是否被经过即可
特殊地,当 \(x \equiv 0\ (\bmod\ y)\ (x \ge y)\) 时:
- 可以 \((x, y) \rightarrow (0, y)\),因此 \(a = 0, b = y\) 时成立
- 可以 \((x, y) \rightarrow (y, y) \rightarrow (y, 0)\),因此 \(a = y,\ b = 0\) 时也成立
注意到 \(a, b, c, d\) 全部取反 / 交换 \(a, b\) 并交换 \(c, d\) 后答案不变
当 \(a, b\) 同号时,可调整到 \(a, b \ge 0\):
- 若 \(c < 0\) 或 \(d < 0\),无解
- 反之,用 \(a, b, c, d \ge 0\) 的方法解决即可
当 \(a, b\) 异号时,可调整至 \(a > 0, b < 0\);先考虑 \(c, d\) 异号的情况:
- 注意到 \(a\) 变号 / \(b\) 变号后就不可能再变回来,因此 \(c < 0, d > 0\) 时无解
- \(a, c\) 同号,\(b, d\) 同号时:
- \((a, -|b|) \rightarrow (a-|b|, |b|)\ (a \ge |b|)\) 可等价到 \((a, |b|) \rightarrow (a-|b|, |b|)\)
- \((a, -|b|) \rightarrow (a, a-|b|)\ (a \le |b|)\) 可等价到 \((a, |b|) \rightarrow (a, |b|-a)\)
- 注意到这就是将 \(y\) 取反,由 \((a, |b|)\) 倒推的过程,现答案等于 \((c, |d|) \rightarrow (a, |b|)\) 的答案
再考虑 \(c, d\) 同号的情况,此时可调整至 \(a > 0, b < 0, c \ge 0, d \ge 0\):
- 由于只能从 \(x\) 轴下跳到上 \(1\) 次,考虑倒推 \((c, d) \rightarrow (0, 0)\),正推 \((a, -|b|) \rightarrow (0, 0)\),考察怎样跳上来合法
- 当正推至 \((x, -|y|)\ (x \ge |y|)\) 时,可能跳到 \((x, x-|y|)\);显然只能从横线上的点向上跳
- 推广到 \((x, -|y|) \rightarrow (x', -|y|)\) 的横线:
- 其经过的点为 \((x, -|y|), (x-|y|, -|y|), \cdots, (x-k|y|, -|y|)\ (x-k|y| \ge |y|)\)
- 能向上跳到的点为 \((x, x-|y|), (x-|y|, x-2|y|), \cdots, (x-k|y|, x-(k+1)|y|)\)
- 注意到,这些点都在 \(f(p) = p-|y|\) 上,且不能跳到竖线上 ( 因为 \(x-k|y| \ge x-(k+1)|y|\) )
- 贪心地,从高到低枚举 \((c, d) \rightarrow (0, 0)\) 的横线 \((x_0, y_0) \rightarrow (x_0', y_0)\) (倒推):
- 算出起跳点 \((p, -|q|)\)
- 维护 \((a, -|b|) \rightarrow (x, -|y|)\) 的贡献
- 算出 \((x, -|y|) \rightarrow (p, -|q|)\) 的贡献
- \((p, -|q|) \rightarrow (p, p-|q|)\) 的贡献为 \(1\)
- 算出 \((p, p-|q|) \rightarrow (x_0, y_0)\) 的贡献
- 维护 \((x_0, y_0) \rightarrow (c, d)\) 的贡献
- 累加,更新答案即可
- 特殊地,当 \(x \equiv 0\ (\bmod\ |y|)\) 时:
- 可以 \((x, -|y|) \rightarrow (|y|, -|y|) \rightarrow (|y|, 0)\)
- 此时直接用 \(a, b, c, d \ge 0\) 的方法算即可
- 别忘了考虑从 \((c, d)\) 倒推到 \((a, b) \rightarrow (0, 0)\) 的终点的贡献
时间复杂度 \(O(n \log^2 V)\)
10.22
P11677 [USACO25JAN] Shock Wave P (观察性质 - 调整法 + 分析变化量 + 优先队列)
以下坐标从 \(1\) 开始
打击 \(x_0\) 一次,相当于施加一个与 \(x\) 轴交点为 \(x_0\) 的绝对值函数
注意到若存在两次打击点为 \(i, j\ (1 < i, j < n)\),调整为 \(i-1, j+1\) 可使两侧变化量相同且中间增大,必定不劣
因此,在 \((1, n)\) 中的打击点至多有 \(1\) 个
先考虑打击点全为 \(1\) 或 \(n\) 时,如何确定答案:
-
二分答案 \(\text{ans}\),不妨设 \(1\) 操作 \(a\) 次,\(n\) 操作 \(b\) 次,有 \(a+b = \text{ans}\)
-
对位置 \(i\),要求 \(p_i \le a(i-1)+b(n-i)\)
-
当 \(2i-1 < n\) 时,移项:
\[\begin{aligned} &p_i \le (a+b)(i-1)+b(n-2i+1) \\ &p_i-(a+b)(i-1) \le b(n-2i+1) \\ &b \ge \frac{p_i-(a+b)(i-1)}{n-2i+1} \end{aligned} \] -
当 \(2i-1 > n\) 时,同理移项:
\[\begin{aligned} &p_i \le (a+b)(n-i)-a(n-2i+1) \\ &a \ge \frac{p_i-(a+b)(n-i)}{2i-1-n} \end{aligned} \] -
当 \(2i-1 = n\) 时,特判即可
-
\(O(n)\) 维护 \(a, b\) 的 \(\max\),判断加起来是否超过 \(\text{ans}\) 即可
-
时间复杂度 \(O(n \log V)\)
注意到,只考虑 \(1, n\) 的 \(\text{ans}\) 至多比真正的 \(\text{ans}\) 大 \(1\),只需检验 \(\text{ans}-1\) 是否成立即可
设 \((1, n)\) 中的操作位置为 \(m\),则我们需要维护:
对位置 \(i\),当操作位置 \(m\) 变化时,\(\max\) 的变化量是 \(\frac{n}{n-2i+1}\) 的
因此,总变化量是 \(O(n \ln n)\) 的
考虑用优先队列维护最值:
- 考虑保证所有位置的 \(\max\) 单调不增,每次尝试更新堆顶,当堆顶不再变化时便可移动 \(m\)
- 先从小到大枚举 \(m\),此时 \(i \le m\) 的 \(\max\) 单调不增,每次加入 \(i = m\) 的值后尝试更新堆顶即可
- 同理,从大到小枚举 \(m\),维护 \(i \ge m\) 的 \(\max\)
- 注意不要把 \(n = 2i-1\) 的 \(i\) 加入堆,特判即可
时间复杂度 \(O(n \log n \log V)\)
10.23
P11675 [USACO25JAN] Photo Op G (set 维护连通块合并与所有答案)
注意到不能走的区域形成了许多四边形块
动态加入线段,维护每个四边形块的 \([x_1, x_2], [y_1, y_2]\)
同时,动态维护所有合法的斜线
合并连通块时,总连通块个数 \(-1\),合并次数是 \(O(n)\) 的,影响的斜线个数是 \(O(1)\) 的
注意起 / 终点为 \(X\) / \(Y\) 的斜线需要特殊维护
set 维护一切,时间复杂度 \(O(n \log n)\)
其实是细节太多了懒得详细写了
10.24
摆烂
10.26
模拟赛
10.26 T1 - 冬夜愚戏之歌 (组合数学 + 容斥 / 生成函数)
法 1:
\(a_i\) 能取负的很烦,考虑变成 \(a_i \in [0, 2k]\),要求 \(\sum\limits_{i=1}^{n} a_i \ge \text{lb}+nk\)
当 \(\sum\limits_{i=1}^{n} a_i = j\) 时,容斥去掉上界,方案数为 \(\sum\limits_{p=0}^{n} (-1)^p \binom{n}{p} \binom{j-2kp+n-1}{n-1}\)
总方案数为 \(\sum\limits_{p=0}^{n} (-1)^p \binom{n}{p} \sum\limits_{i=\text{lb}+nk}^{2nk} \binom{i-2kp+n-1}{n-1}\)
由公式 \(\sum\limits_{i=0}^{n} \binom{i}{k} = \binom{n+1}{k+1}\) (证明考虑补上 \(\binom{0}{k+1}\),由 \(\binom{n}{k} = \binom{n-1}{k-1} + \binom{n-1}{k}\) 滚雪球即可),后面的和式容易算
线性求逆元,预处理阶乘及其逆元求组合数,时间复杂度 \(O(Tnk)\)
法 2:
仍然先转化为 \(a_i \in [0, 2k]\)
考虑生成函数,设答案的生成函数为 \(F(x)\),多填一个数相当于乘上 \(G(x) = 1+x+x^2+\cdots+x^{2k}\)
\(F(x)\) 的初值为 \(1\),最终答案的生成函数即为 \(G^n(x)\)
用二项式定理暴力求 \((1-x^{2k+1})^n\) 即可,有值的位置只有 \(n\) 个
时间复杂度 \(O(Tnk)\)
10.26 T2 - 方格取数 (转化限制 + 高维前缀和)
记 \(m\) 为路径总数,直接暴力枚举相邻的折线可以做到 \(O(km^2)\)
考虑如何刻画 "相邻折线"
对一条折线,记其经过的第 \(i\) 列的最靠下的位置为 \(v_i\)
则折线 \(\{v'\}\) 在折线 \(\{v\}\) 下方等价于 \(\forall i,\ v'_i \ge v_i\)
注意到这实际上就是做 \(k-1\) 次高维前缀和
枚举 \(k\),令 \(f_{\{v\}}\) 表示选了前 \(k\) 条路径,最下方的路径为 \(\{v\}\) 的所有方案价值和
朴素转移为 \(f_{\{v\}} \leftarrow f_{\{v\}}+f_{\{v'\}}\ [\forall i,\ v_i \ge v'_i]\)
按照高维前缀和的思想,从高到低枚举每位 \(\text{bit}\) (从 \(1\) 开始),转移为:
-
\(f_{\{v_1, v_2, \cdots, v_{\text{bit}}, \cdots, v_{n}\}} \leftarrow f_{\{v_1, v_2, \cdots, v_{\text{bit}}, \cdots, v_{n}\}} + f_{\{v_1, v_2, \cdots, v_{\text{bit}}-1, \cdots, v_{n}\}}\ [v_{\text{bit}}-1 \ge v_{\text{bit}-1}]\)
-
当然,这是错的
以路径 \(\{1, 1, 3\}, \{1, 2, 3\}, \{1, 3, 3\}\) 为例,所有路径的权都是 \(1\):
- 初始时,\(f_{\{1, 1, 3\}}, f_{\{1, 2, 3\}}, f_{\{1, 3, 3\}} = 1\)
- 先进行转移 \(f_{\{1, 2, 3\}} \leftarrow f_{\{1, 2, 3\}}+f_{\{1, 1, 3\}}\),此时 \(f_{\{1, 2, 3\}} = 2\)
- 再进行转移 \(f_{\{1, 3, 3\}} \leftarrow f_{\{1, 3, 3\}}+f_{\{1, 2, 3\}}\),此时 \(f_{\{1, 3, 3\}} = 3\)
- 但是,\(f_{\{1, 3, 3\}}\) 应该为 \(4\),即 \(\{\{1, 1, 3\}, \{1, 3, 3\}\}, \{\{1, 2, 3\}, \{1, 3, 3\}\}\) 两种方案的价值和
为什么错?容易发现,\(f_{\{1, 3, 3\}}\) 本来应该算 \(2\) (方案个数) 次,我们却只算了 \(1\) 次
因此,令 \(f'_{\{v\}}\) 表示选了前 \(k\) 条路径,最下方的路径为 \(\{v\}\),暂不考虑 \(\{v\}\) 本身的贡献,所有方案的价值和
再令 \(g_{\{v\}}\) 表示选了前 \(k\) 条路径,最下方的路径为 \(\{v\}\),总的方案数
-
真正的转移为
-
先从高到低枚举 \(\text{bit}\):
\(f_{\{v_1, v_2, \cdots, v_{\text{bit}}, \cdots, v_{n}\}} \leftarrow f_{\{v_1, v_2, \cdots, v_{\text{bit}}, \cdots, v_{n}\}} + f_{\{v_1, v_2, \cdots, v_{\text{bit}}-1, \cdots, v_{n}\}}\ [v_{\text{bit}}-1 \ge v_{\text{bit}-1}]\)
这里 \(f_{\{v\}}\) 维护的是选了前 \(k-1\) 条路径,最下方的路径为 \(\{v\}\),考虑了 \(\{v\}\) 的贡献,所有方案的价值和
随着 \(\text{bit}\) 的改变,\(f_{\{v\}}\) 相当于 \(k-1\) 条路径的方案价值和的高维前缀和
注意,\(k\) 条路径的方案价值和不是 \(f_{\{v\}}\)!
\(f'_{\{v_1, v_2, \cdots, v_{\text{bit}}, \cdots, v_{n}\}} \leftarrow f'_{\{v_1, v_2, \cdots, v_{\text{bit}}, \cdots, v_{n}\}} + f_{\{v_1, v_2, \cdots, v_{\text{bit}}-1, \cdots, v_{n}\}}\ [v_{\text{bit}}-1 \ge v_{\text{bit}-1}]\)
这里 \(f'_{\{v\}}\) 维护的东西同上述定义
这个转移的意义为在 \(f_{\{v'\}}\) 的基础上再拼上 \(\{v\}\),从 \(k-1\) 条路径变成 \(k\) 条;但 \(\{v\}\) 的贡献并不现在算
由于 \(f_{\{v\}}\) 已经代表高维前缀和,无需从所有 \(\{v'\}\) 转移,从 \(\{v\}\) 的上一个转移即可
\(g_{\{v_1, v_2, \cdots, v_{\text{bit}}, \cdots, v_{n}\}} \leftarrow g_{\{v_1, v_2, \cdots, v_{\text{bit}}, \cdots, v_{n}\}} + g_{\{v_1, v_2, \cdots, v_{\text{bit}}-1, \cdots, v_{n}\}}\ [v_{\text{bit}}-1 \ge v_{\text{bit}-1}]\)
这里 \(g_{\{v\}}\) 其实同时维护了高维前缀和 / 当前 \(k\) 条路径的方案数
按维护 \(f_{\{v\}}\) 的方式写成 \(g_{\{v\}}\) 与 \(g'_{\{v\}}\) 当然没问题,不过这里没有 \(\{v\}\) 需要重复贡献的问题,可以合并
-
枚举完 \(\text{bit}\) 后:
\(g_{\{v\}} \leftarrow g_{\{v\}} - \text{tmp}_{\{v\}}\),\(\text{tmp}_{\{v\}}\) 表示选 \(k-1\) 条路径时 \(g_{\{v\}}\) 的值
注意到 \(g_{\{v\}}\) 的转移中其实多考虑了从 \(k-1\) 条路径时的 \(g_{\{v\}}\) 转移来的贡献
换句话说,我们多算了上一条是 \(\{v\}\),这一条还选 \(\{v\}\) 的贡献,这其实是不合法的
因此减去即可
\(f_{\{v\}} \leftarrow f'_{\{v\}} + g_{\{v\}} \cdot w_{\{v\}}\),\(w_{\{v\}}\) 代表路径 \(\{v\}\) 的价值和
这个转移表示加上之前暂时没有考虑的 \(\{v\}\) 的贡献
-
-
初始值为:
- 全局初始值为 \(f_{\{v\}} = w_{\{v\}},\ g_{\{v\}} = 1\)
- 在每次 \(k \rightarrow k+1\),枚举 \(\text{bit}\) 前,将 \(f'_{\{v\}}\) 清零
-
答案为 \(k! \cdot \sum\limits_{\{v\}} f_{\{v\}}\)
-
实现细节上:
-
可以对 \(\{v\}\) 进行 hash,预处理某一位减 \(1\) 后的 \(\{v'\}\) 的编号
-
需要按照 \(v_{\text{bit}}\) 从小到大对 \(\{v\}\) 排序,这样高维前缀和才是对的
-
我们假装没有不合法的路径
换句话说,我们仍枚举每个不合法路径并转移
对不合法路径,视其初始值为 \(f_{\{v\}}, g_{\{v\}} = 0\),最终仍为 \(0\)
这样逐位 \(-1\) 转移才是对的
-
时间复杂度 \(O(knm)\)
10.26 T3 - 这是我新买的象棋波特 (观察性质 + 贪心)
考虑枚举答案所在列 \(i\)
容易发现,若最优方案中离 \(i\) 更远列能合并到 \(i\) 上而更近列不能,必能调整使得更近列合并到 \(i\) 上
因此,会有一段前缀 \([l_i, i-1]\) 与一段后缀 \([i+1, r_i]\) 合并到 \(i\) 上
考虑贪心,从前向后扫,每次优先让最低的棋子移到下一列,维护前缀合并的最优方案;后缀同理
由于叠棋子的总数是 \(O(m)\) 的,时空复杂度没有问题
合并 \(i-1, i+1\) 时,将所有棋子从低到高排序,按相同策略合并即可
可以双指针维护,时间复杂度 \(O(m \log m + n)\)
10.26 T4 - 偶数题 (转化限制 - 赋势能 + 树形 DP)
首先容易观察出 type 为 \(0\) 时答案为 \(D\),其中 \(D\) 为直径长度的一半
证明考虑以直径中点为根,按深度奇偶赋值即可
这启示我们以直径中点为根考虑;记 \(\text{dep}_i\) 为点 \(i\) 到根经过的边数,\(\text{dis}_{i, j}\) 为点 \(i, j\) 间简单路径的边数
考虑给每个点赋势能 \(h_i\) 以刻画 \(f(P)\)
注意到 \(P\) 中边数确定,若知道两种方向的边的数量之差,就能算出 \(f(P)\)
因此,我们要求对定出的有向边 \(u \rightarrow v\),满足 \(h_v = h_u - 1\)
因此有 \(\displaystyle f(P) = \frac{\text{dis}_{u, v}+|h_u-h_v|}{2}\),其中 \(u, v\) 为路径两端点
注意到对所有可能成为直径两端点的点 \(u, v\),有 \(h_u - h_v = 0\);因此令所有 \(\text{dep}_u = D\) 的点 \(u\) 的势能为 \(0\)
限制转化为 \(\forall u, v,\ |h_u-h_v| \le 2D-\text{dis}_{u, v}\)
考虑将 \((u, v)\) 的限制转化为 \(u, v\) 各自的限制;因此,我们希望对每个点考察其最严的限制
感性理解上,路径越长,限制越严;可以猜测 \(\text{dep}_v = D\) 时限制最严,为 \(|h_u| \le D-\text{dep}_v\)
证明充分性:\(|h_u-h_v| \le |h_u|+|h_v| \le (D-\text{dep}_u)+(D-\text{dep}_v) \le 2D-\text{dis}_{u, v}\)
因此,只需满足:
- 当 \(\text{dep}_u = D\) 时,令 \(h_u = 0\)
- 对边 \((u, v)\),有 \(|h_u-h_v| = 1\)
- 对点 \(u\),有 \(|h_u| \le D-\text{dep}_u\)
记 \(f_{u, w}\) 表示考虑 \(u\) 子树,\(h_u = w\) 的方案数,对 \(h_u\) 树形 DP 即可
时间复杂度 \(O(n^2)\)

浙公网安备 33010602011771号