26DMYCSP-S#3
Daimayuan CSP-S 2026 Round 3
闲话
貌似是搬的 ICPC 网络赛题,有个题 \(2 \text{s}, n = 10^6\) 直接改成 \(1 \text{s}, n = 2 \times 10^6\),有点变态了。
开考看了四个题,T1 看上去要么是简单题,要么是很变态的数据结构。T2 一眼有个 \(\mathcal{O}(n^2)\) 的 DP,估计是考察重点在数据结构优化/决策单调性优化的题。T3 看上去是比较复杂但不 Ad-hoc 的构造。T4 一眼困难 DS,结构很复杂,一眼只能看出必定是最后 \(k\) 次插入的结论,其他目前想不明白。
直接做 T1,注意到直接建 Trie,维护每个节点的遍历次数以及每个长度对应的最大的 \(j\) 即可做到 \(\mathcal{O}(n|\Sigma| + \sum |s_i|)\),从开想到过大样例一共大概 \(10\) 分钟左右。
然后 T2 想了一会只会 \(\mathcal{O}(n^2)\),顶多就是对 \(r_i - y_i\) 和 \(r_i - b_i\) 两维限制硬用 DS 优化,三维偏序做到 \(\mathcal{O}(n \log^2 n)\),解决不了问题。
看 T3,首先容易将统计的量转化为每个位置如果是村民那么前缀需要有多少个狼,要么是 \(b_i\) 要么是 \(k - b_i\)。所以实际上可以将狼看作若干个离散的段,首先按照所有都是村民的情况来做,然后枚举调整不得不选狼对应的约束。实际上转移可以看作 \(2 \times 2\) 的布尔矩阵转移,每个矩阵的卷积顺序是固定的,所以可以直接 ST 表维护,那么可以直接 \(\mathcal{O}(n \log n)\)。进一步你发现总的状态数要么是一整段 \(n\) 要么是 \(\mathcal{O}(1)\),所以直接对去重后的总状态 DP 就可以做到 \(\mathcal{O}(n)\) 了。这个既难想又难写,想+写+卡常一共 \(3 \text{h}\) 左右。
这时候已经没剩下多少时间了,于是只写了一个 T2 的二维 BIT 和 T4 的 \(n, q \leq 2000\)。最终 \(100+60+100+10\),rk 10,没挂。
感觉问题还是原来那几个:
- 代码能力和卡常能力不够,总是不该 DFS 的地方 DFS 导致回滚的时候思维链过于冗长,控制不好换角度的时间。
- DS 问题中刻画复杂结构的能力比较差,很多时候还是会漏掉条件端或者所求统计量那一端的一些基础条件,导致做法复杂化。
- 对决策单调性的理解还是不够,转化到贪心问题的那一步总是选错结构或者量导致问题复杂化。
T1
tag:Trie 树。
考虑按照 \(i = 1,2,3,\dots,n\) 的顺序把 \(n\) 个串全部插到一棵 Trie 内。对每个点记录 \(c_j\) 表示这个点 \(j\) 当前被遍历到的次数,它等价于 \(f(i,c_j) \geq \text{dep}(j)\) 的约束。
那么只需要维护 \(d_i\) 表示遍历次数等于 \(i\) 的 \(f\) 最大值,初始时只需要考虑一个串对应的答案,因为一个串的 LCP 就是它自己所以直接就是 \(i\)。然后每次修改 \(d_i\) 的时候对应修改它对答案的贡献即可。
T2
tag:DP 优化、树状数组。
首先可以设 \(f_i\) 表示考虑前 \(i\) 个位置,固定 \(i\) 作为最后一段结尾的最大权值。那么转移就是枚举当前这一段的左端点,有 \(f_i = \max\limits_{1 \leq j \leq i} \{\text{W}(i,j) + \max\limits_{1 \leq k \lt j} f_k\}\),其中如果 \([i,j]\) 符合条件就有 \(\text{W}(i,j) = i - j + 1\),否则 \(\text{W}(i,j) = 0\)。则可以直接记录前缀 \(\max\) 做到 \(\mathcal{O}(n^2)\)。
然后可以将题目给的约束转化为 local 的部分,考虑前缀和,令 \(p_i = r_i - b_i\),\(q_i = r_i - y_i\),那么当且仅当 \(p_r \geq p_l\) 并且 \(q_r \geq q_l\) 的时候段 \([l,r]\) 是合法的,到这里转化成三维偏序,可以做到 \(\mathcal{O}(n \log^2 n)\)。
进一步考虑,对于一个合法区间 \([l,r]\),如果调整到 \([l,r + 1]\) 也合法,那么这样做能让当前区间的段长 \(+1\),同时因为 \(r_i, b_i, y_i \leq 1\) 所以直接这样调整也不会让后面一段变劣的程度超过 \(1\),由此我们知道直接这样贪心调整必定是不劣的,换言之只有 \(p_r = p_l\) 或 \(q_r = q_l\) 或 \(l = 0\) 的情形是需要考虑的。由此可以直接按照 \(p,q\) 的取值将原问题划分为 \(\mathcal{O}(n)\) 个等价类,每个等价类中的问题等价于二维偏序,等价类大小之和 \(\mathcal{O}(n)\),故可以做到 \(\mathcal{O}(n \log n)\)。
T3
tag:DP、状态优化、ST 表。
设总共有 \(k\) 个狼,则可以直接求出第 \(i\) 个位置如果是人,前缀需要有多少个狼,记为 \(c_i\),那么如果 \(d_i = \texttt{L}\) 就有 \(c_i = b_i\),否则是 \(c_i = k - b_i\)。则问题变成了有 \(\mathcal{O}(n)\) 个前缀约束,要求你构造一组满足所有前缀约束的解。
则可以直接 DP,设 \(f_i\) 表示第 \(i\) 个位置能否是人,找到前一个人的位置为 \(j\) 那么需要有 \(i - 2 \leq j \leq i - 1\),合法转移有:
- 如果是 \(d_j = \texttt{L} \to d_i = \texttt{L}\),那么要求 \(b_i = b_{j} + (i - j - 1)\) 则可以 \(f_j \to f_i\)。
- 如果是 \(d_j = \texttt{R} \to d_i = \texttt{R}\),那么要求 \(b_j = b_i + (i - j - 1)\) 则可以 \(f_j \to f_i\)。
- 如果是 \(d_j = \texttt{L} \to d_i = \texttt{R}\),那么要求 \(b_i = k - b_j - (i - j - 1)\),则可以 \(f_j \to f_i\)。
- 如果是 \(d_j = \texttt{R} \to d_i = \texttt{L}\),那么要求 \(b_i = k - b_j + (i - j - 1)\),则可以 \(f_j \to f_i\)。
一个简单的思路是可以把转移写成 \(2 \times 2\) 的布尔矩阵转移,又因为转移顺序固定,可以直接用 ST 表维护区间内,位置离散意义下的矩阵的复合结果做到 \(\mathcal{O}(n \log n)\)。
进一步优化,考虑维护两个转移集合 \(T_i,S_i\),前者表示只考虑每次转移的条件,不考虑总数是否恰为 \(k\),所有合法的 \(k\) 值集合。\(S_i \subseteq T_i\) 表示进一步考虑 \(T_i\) 中的取值,只有真的存在一个前缀分布能满足条件才属于 \(S_i\)。
那么对 \(T_i\) 而言,转移等价于直接找出 \(E_{1,i},E_{2,i}\) 表示满足从 \(i-1,i-2\) 转移条件的集合,则有 \(T_i = (T_{i-1} \cap E_{1,i}) \cup (T_{i-2} \cap E_{2,i})\)。因为只需要处理 \(d_i = d_{i-1}\) 或 \(d_i = d_{i-2}\) 的约束所以 \(E_1,E_2\) 要么是空集,要么是全集。对一条转移链上面方向相同的一段,如果出现全集,只要之后有一个全集转移就能直接继承,还是全集。否则如果当前不是全集这一段内就必定不会产生新的 \(k\),每次方向转变的时候至多插入 \(2\) 个单点值,所以总状态数是线性的,因为最后至多只有常数个可能的 \(k\) 留下,所以还原出 \(S_n\) 只需要对这常数个 \(k\) 重新 DP 一次确保每一步总数都不超过 \(k\) 即可。总时间复杂度 \(\mathcal{O}(n)\)。
T4
tag:贪心、扫描线、树状数组。
首先因为我们希望 mex 尽可能大所以肯定是最后 \(k\) 次用操作 2。那么直接对每组询问的 \((m,k)\) 算答案可以做到 \(\mathcal{O}(n^2)\)。
让我们刻画清楚每个前缀对应的答案到底会是什么,求出 \(b_1 \lt b_2 \lt \dots \lt b_k\) 对应没有在前缀 \(a_{[1,m]}\) 中出现的数从小到大排列的情况。那么答案必定出现在 \(b\) 中。进一步地,令询问给定第二维是 \(k\) 的答案为 \(b_{q_k}\),则必定有 \(q_k \leq q_{k+1} \leq q_{k} + 1\),因为一次操作至多能填一个空。由此,考虑直接维护 \(q\),令当前答案为 \(b_j\),新加进来一个会对问题产生影响(即此时前缀内不存在和它相同的值)的 \(a_i\),对 \(b_j\) 的影响是:
- 如果 \(a_i \lt b_j\) 那么无影响。
- 如果 \(a_i = b_j\),那么实际上一方面 \(a_i\) 填了一个空,另一方面 \(j\) 又增加了 \(1\),所以实质上无影响。
- 如果 \(a_i \gt b_j\),那么有一个 \(j \leftarrow j + 1\) 的影响,等价于后缀 \(+1\) 操作。
处理完 \(a_i\) 之后,第 \(i\) 个位置必定进行一次 mex 操作,因此下标 \(q_k\) 整体再 \(+1\),也就是 \([1,i]\) 前缀中 \(k\) 对应的问题的答案等价于 \([1,i-1]\) 中 \(k - 1\) 的答案,如果在 \([1,i-1]\) 中,\(q_{k-1}\) 对应的答案满足 \(b_{q_{k-1}} \leq a_i\) 那么还要 \(+1\)。这个可以反过来维护每个前缀的偏移量,则只需要树状数组。时间复杂度 \(\mathcal{O}((n + q) \log n)\)。
浙公网安备 33010602011771号