A2OJ Ladder 32 简要题解

发布时间 2023-11-17 09:04:56作者: LarsWerner

https://earthshakira.github.io/a2oj-clientside/server/Ladder32.html

只记录 Difficulty level >= 8 的。有很多题是口胡的。写了的会标注提交记录。还有些很久以前写过的题就懒得搬提交记录了。任何的 * 都表示该段的后续部分未能想出并查看了题解。

159. CF372D Choosing Subtree is Fun

双指针,然后维护虚树大小。\(O(n\log n)\)

160. CF235C Cyclical Quest

考虑建出后缀树,然后对问询串的每个循环同构定位到后缀树节点。我们先定位原串,然后每次做一次循环同构,就相当于是跳一次后缀 link。然后我们每次需要检查这条边上的字符串的某一段是否等于问询串的某一段,这个可以直接哈希。

161. CF367E Sereja and Intervals

由于只有 \(n<m\) 才有解,所以可以复杂度 \(O(n^m)\)。考虑把问题转成两条平面上的路径 \(l\)\(r\),要满足 \(r_i\ge l_i\) 且每一步都要往上走,且存在一点 \(l_i=x\)。于是我们考虑转置,即从下往上 DP 而不是从左往右 DP:\(f(i,j,k)\) 表示仅考虑 \(\le i\) 的数,第一个 \(\ge i\) 的左端点是 \(l_j\),第一个 \(\ge i\) 的右端点是 \(r_j\)。然后就可以直接 DP了。

https://codeforces.com/contest/367/submission/232162972

162. CF406E Hamming Triples

首先考虑三个这样的 string 的汉明距离之和,其实就是两倍的非全0/1的位的个数,上界为 \(2n\)。取到上界的情况(假设取了两个 \(0\) 一个 \(1\),相反情况对称):考虑枚举 \((1,z)\),那么需要一个 \((0,\ge z)\),一个 \((0,\le z)\),这是容易统计的。取不到上界的情况:那么先算得答案 \(p\),枚举 \((1,z)\),那么需要 \((0,z+p)\)\((0,z-p)\);然后还有可能在三个 \(0\) 或三个 \(1\) 处取到,此时需要 \(n-\max+\min=p\),都是可以直接求的。

163. CF512E Fox and Polygon

考虑建出三角剖分树:即树的每个节点代表一条连接 \((l,r)\) 的边,然后边 \((l,r)\) 代表的节点连接所有 \((l,x)\) 满足 \(x\in(l,r)\)。于是我们每次操作 \((l,r)\) 就是把 \((l,r)\) 节点的最后一个儿子给拆到父亲上去。于是我们由浅至深,每个 \((l,r)\) 都从后往前操作所有的 \((l,x)\) 满足 \((l,x)\) 有边,就能把树变成一棵菊花。然后我们也可以找到把目标树变成菊花的方法,然后再把这些操作换成其逆操作即可。

https://codeforces.com/contest/512/submission/232169658

164. CF704C Black Widow

我们把每个表达式连边,最终形成的图会是一堆环加一堆链。对于环和链,我们都可以进行线性的 DP。链上 \(f(i,0/1,0/1)\) 表示前 \(i\) 个点,第 \(i\) 个点为 \(0/1\),这些边上的式子异或起来得到 \(0/1\)。环上还需要找一个点,枚举其为 \(0/1\) 然后破环为链。

165. CF261D Maxim and Increasing Subsequence

考虑 DP:\(f(i,j)\) 表示目前考虑到 \(\le i\) 的数,选了 \(j\) 个数,最小的最后一个数的位置。转移可以从 \(f(i-1,j)\) 转移,也可以从 \(f(i-1,j-1)\) 转移,需要处理出 \(p_{i,x}\) 表示 \(i\) 之后的第一个 \(x\) 的位置。

166. CF493E Vasya and Polynomial

谔谔题。首先注意到 \(a_0\equiv a\pmod t\)\(a_0\equiv b\pmod a\)\(a_0\le a\)。也就是说,如果 \(a\nmid b\) 那么 \(a_0\) 是固定且非 \(0\),然后就可以递归下去:因为递归下去后有 \(a_1\equiv b/a_0\pmod a\)\(a_1\le a/a_0\),同样可以得到上述结论。然后如果 \(a\mid b\),那么 \(a_0=0\)\(a_0=a\)。这两种同时合法当且仅当 \(t=a=b\)。仅后者合法当且仅当 \(a=b\)。有关前者可以直接递归下去。特判 \(t=1,a=1,b=1\) 有无穷解。

https://codeforces.com/contest/493/submission/232187176

167. CF739E Gosha is Hunting

先对 \(a\) wqs二分,再对 \(b\) wqs 二分,然后直接 DP,复杂度 \(O(n\log^2 n)\)

168. CF679D Bear and Chase

阅读理解题。考虑枚举选择哪个点 \(u\),统计一下 \(f(u,d)\) 表示到 \(u\) 距离为 \(d\) 的点的个数,以及 \(g(u,d,-1/0/1)\) 表示有多少组 \((x,y)\) 满足 \(d(u,x)=d\)\(d(u,y)=d-1\)\(d\)\(d+1\)。统计完这个之后就可以直接做了。复杂度 \(O(n^3)\)

169. CF311C Fetch the Treasure

考虑每次修改之后做一次同余最短路,就能确定出哪些宝藏是可以选到的。剩下两个操作的维护是 trivial 的。

170. CF351D Jeff and Removing Periods

题目相当于做区间数颜色+是否存在一个数使得在区间中出现位置成等差数列。区间数颜色直接做,后面一个,我们处理出每个颜色的所有极长成等差数列的区间的集合 \(S\),然后我们相当于需要看问询区间是否被 \(S\) 中一个区间包含,扫描线直接做。

171. CF482D Random Function and Tree

考虑 DP:\(f(u)\) 表示 \(u\) 子树的染色方案数。然后考虑转移,然后乘以二表示正着遍历儿子和反着遍历有区别。考虑什么时候会算重,即什么时候没区别:所有染了的儿子节点的染的个数都为偶数,或者全为奇数且有奇数个被染的。于是我们改状态记录 \(f(u,0/1)\) 表示子树染了奇数/偶数个的方案数,然后转移时减掉上述的重复的即可。

https://codeforces.com/contest/482/submission/232226492

172. CF763D Timofey and a flat tree

使用最好的 xor-shift 树哈希。xor-shift 树哈希很支持换根,每次只要把子树的贡献加加减减即可。

https://codeforces.com/contest/763/submission/232242300

173. * CF464D Work of Darkraft

考虑 DP,求出每一个装备的期望收益,\(f(i,j)\) 表示等级为 \(j\) 的跑 \(i\) 轮后期望收益。由于题目是小数输出,并且规定相对误差,而如果等级太高那么达到的可能性过小了,所以 \(j\) 只要取 \(\le 1000\) 即可。

https://codeforces.com/contest/464/submission/232386545

174. CF516D Drazil and Morning Exercise

首先注意到这个 \(f\) 很有性质。如果我们直径的中心作为根,那么我们就发现 \(f\) 满足 \(f_{son}=f_u+1\),所以问题转化为了对于每个子树,求出 \(g_{u,l}\) 表示 \(u\) 子树中到 \(u\) 的距离 \(\le l\) 的点的个数。记 \(d_{u,l}\) 表示距离 \(=l\) 的点数,那么长剖维护 \(d\) 的后缀和即可。复杂度是 \(O(nq)\)

175. CF582E Boolean Function

\(f(u,S)\) 表示表达式树节点 \(u\),每个函数的值的状态压缩为 \(S\) 的方案数。容易发现转移为 or 卷积和 and 卷积,所以 fmt 一下即可。\(O(nm2^m)\)

https://codeforces.com/contest/582/submission/232441844

176. CF504D Misha and XOR

直接 bitset 维护现线性基,然后需要比较精细的高精度实现吧。感觉一整个无意义题。

177. * CF559D Randomizer

考虑算减掉的整点数的期望。整点个数由皮克定理可以获得,所以我们需要求期望面积以及边界整点数。考虑枚举 \(i,j\) 满足 \(i\)\(j\) 中间的点全部都被删掉了。但是 \(j-i\) 大了的时候概率就很小,所以只需要处理 \(j-i\le 50\) 的就行了。

178. CF671D Roads in Yusland

考虑一种贪心。我们先考虑对于叶节点 \(u\),有一些向覆盖其父边的链。我们考虑取其权值最小值 \(p\) 作为覆盖父边的代价,然后把剩下的链的权值全部减去 \(p\),全部给父节点。维护这个过程可以用一个堆,然后每个节点维护一个减法 tag,然后启发式合并堆即可。可并堆也是可以的。

https://codeforces.com/contest/671/submission/232470702

179. CF741D 题目名称很长

没啥意思的 DSU on tree 板子题。考虑状压,需要对 \(u\) 维护出个 \(v\)\((u,v)\) 路径上的字符集的 xor-hash,然后对于这些状压,然后对于每种状态记录深度最大的 \(v\)。显然这个可以直接 dsu on tree 维护,复杂度 \(O(2^{|\Sigma|}+n|\Sigma|\log n)\),能过。

180. CF568C New Language

直接 2-SAT 建图之后,硬贪心。分析一下复杂度 \(O(n^3)\)。有可观的细节要处理。

181. CF576D Flights for Regular Customers

考虑把限制转化为第 \(i\) 条边只有在 \(\ge d_i\) 的时刻才会开放,然后每个时刻得走一条边。于是我们用矩阵乘法的方式来模拟这个过程,由于是 01 矩阵所以可以 bitset 加速,这个模拟的复杂度 \(O(n^4\log d /w)=O(n^4)\)。然后注意到我们到达终点的时刻,一定可以通过我们对每次开放新边之后 bfs 一次来算出,此处复杂度 \(O(m^2)\)

182. * CF283E Cow Tennis Tournament

考虑一个转化:三个点不形成三元环,当且仅当其中存在一个点在这两个点中出度为 \(2\)。也就是说我们通过计算 \(\sum \binom{\deg_i}{2}\) 就可以得知非三元环的个数。这个可以直接线段树扫描线求。

https://codeforces.com/contest/283/submission/232722815

183. CF232D Fence

考虑把原数组差分后,这个条件相当于变成了差分互为相反数。这个强于数子串出现个数。直接把正差分和反差分拼接后建出后缀树,问题转化为子树的 startpos 集合中有多少位于 \([1,l_i-len]\)\([r_i,n-len]\)。离线下来扫描线维护线段树即可。

184. * CF261E Maxim and Calculator

首先注意到步数一定大于最小素因数。然后一个重要结论:最小素因数 \(<100\) 的在 \(10^9\) 的数只有约 \(n=3\times 10^6\) 个!

然后就简单了。考虑从小到大枚举 \(b\) 的最大取值 \(x\),然后维护 \(f_i\) 表示在仅使用 \(\le x\) 时最小乘法次数,于是每次用 \(f_{i/x}\) 去更新 \(f_i\),并看是否 \(f_i+x\le p\) 并更新答案。由于 \(i\) 可能太大了,所以考虑离散化后,注意到 \(i/x\) 也是递增的,所以另维护指针 \(j\) 表示 \(i/x\) 的位置,可以做到 \(O(pn)\)

185. * CF573E Bear and Bowling

需要猜个决策包容性,即每次只需要选择当前最优的决策即可。

然后就维护每个值在当前状况下带来的贡献,一定是一个斜率为 \(i\) 的的一次函数,然后需要区间 \(x+\),区间 \(b+\),然后求 \(kx+b\) 最大值。KTT,启动!

186. CF573D Bear and Cavalry

首先考虑把 \(a,b\) 排序,然后考虑最终形态。最优情况一定是 \(\sum a_ib_i\) 但是实际上可能存在 \(p_i=i\) 所以不合法。但是我们注意到,首先我们根本不需要管 \(p_i\neq i\) 时限制,因为如果我们这样连边一定存在更优的不这样配且合法的做法。所以现在变成了一堆要求不能 \(a_i\)\(b_i\) 配对的限制。并且我们发现如果存在跨度 \(>2\) 的配,那么一定可以调整。所以最终 \(i\) 只能配 \(i,i-1,i-2\)。线段树维护 (min,+) 矩阵动态 DP 即可。

https://codeforces.com/contest/573/submission/229688099

187. CF603E Pastoral Oddities

首先观察到,如果连通块点的个数为奇数那么显然不可能构造成功。否则一定可以对着 dfs 树直接构造。于是现在问题就变成了,在加入了前 \(m\) 条边时,求最小的边权 \(p\) 使得 \(\le p\) 的边组成的图只存在偶连通块。这个东西显然是单调的,所以考虑整体二分,维护一个可撤销并查集。复杂度 \(O(m\log n\log m)\)

188. CF280D k-Maximum Subsequence Sum

法一:考虑这玩意儿是凸的,所以 (max,+) 卷积是线性的。线段树上每个维护向量 \(l\) 表示钦定包含左端点的答案,\(r\) 选择钦定包含右端点的答案,\(f\) 表示总的答案,\(g\) 表示钦定包含左右端点的答案。 合并的时候需要用 \(f_{ls},r_{rs},r_{ls}*l_{rs}\) 更新 \(f\)\(r_{rs},r_{ls}*g_{rs}\) 更新 \(r\)\(l_{ls},g_{ls}*l_{rs}\) 更新 \(l\)\(g_{ls}*g_{rs},l_{ls}*r_{rs}\) 更新 \(g\),其中 \(*\) 操作表示 (max,+) 卷积。

法二:考虑求 k-子段最大和的反悔贪心做法:每轮都找到最大子段,然后将子段取反,这样做 \(k\) 轮。于是我们维护一个支持区间取反,区间查最大子段,以及单点更新的线段树。然后每次问询就模拟这个过程。两个方法复杂度都是 \(O(mk\log n)\) 的。

189. CF453D Little Pony and Elements of Harmony

首先我们注意到对于 \(x,y\)\(x\)\(y\) 的贡献可以用 \(e_{x}\times c_{x,y}\) 表示,而 \(c_{x,y}\) 一定只和 \(\operatorname{popcount}(x\oplus y)\) 有关。由于这玩意儿只有 \(m\) 种,写出其递推关系并用矩阵快速幂进行优化。我们不妨假设最初的 \(x=0\)。令 \(f_{i}\) 表示对于一个固定的含有 \(i\)\(1\) 的数 \(y\)\(c_{0,y}\) 会是多少。于是 \(f_i\to f'_j\) 的转移系数即为 \(\sum_k \binom{j}{k}\binom{m-j}{i-k}b_{i+j-2k}\)。用矩阵快速幂优化后,我们只需要对于每个 \(y\) 算出 \(\sum_x e_xc(0,x\oplus y)\)。这个是经典的 FWT 问题。所以总复杂度 \(O(2^mm+m^3\log T)\)。由于只需要乘一次,所以开个 int128 然后最后再取模就能解决。

* 补充:其实可以不需要矩阵乘法,而是直接做异或卷积快速幂。而这个快速幂由于不存在循环卷积的问题,所以可以 先 FWT 一次之后直接做整数快速幂。而关于逆元的问题,可以像 FFT 在最后再除以向量长度。然后我们可以先对 \(p\times 2^m\) 取模,这样除得的答案就是模 \(p\) 的余数了。同样需要 int128。

https://codeforces.com/contest/453/submission/232734607

190. CF480E Parking Lot

套路题。考虑维护 \(f_{i,j}\) 表示 \((i,j)\) 最多向上延申多少,\(g_{i,j}\) 表示向下。那么对于每一行,算出最终正方形包含这一行的面积:即对右端点扫描线,然后维护最小的左端点满足能够以这两个端点构成一个正方形,并维护 \(f,g\) 的滑动窗口最大值。每次更新只会更新 \(O(n)\)\(f,g\),并且如果我们倒序做的话,新增的正方形一定包含修改的那一行,所以只需要算一行的答案即可。

191. CF232E Quick Tortoise

考虑平面分治。每次取短边。假设短边为纵向,那么对于短边上的每个点,处理出能到达它的左侧点以及它能到达的右端点,这个可以用 bitset 去优化。复杂度 \(T(S)=2T(n/2)+S\sqrt{S}/w\),其中 \(S\) 为面积,于是总复杂度 \(O(n^3+qn)\)

* 补充:采用 AGC028F Reachable Cells 中的做法,即每个点找到每行的最左可达点以及最有可达点,以及每个点找到能到达这个点的字典序最小的 \((x,y)\),即可做到 \(O(n^3+q)\)

192. CF453E Little Pony and Lord Tirek

首先可以暴力处理每个位置被第一次修改的时候的情况。然后问题转化为每个点维护一个 \(d_i\) 表示上一次被问询的时刻。我们对 \(d_i\) 颜色段均摊,即每次问询找到 \(d_i\) 相同的连续段,然后问区间 \(\min(m_i,(T-d)r_i)\)。这个可以直接用主席树做,即对于区间求 \(m_i/r_i\ge T-d\)\(r_i\) 之和以及 \(m_i/r_i<T-d\)\(m_i\) 之和。所以可以做到均摊 \(O((n+m)\log V)\)

193. CF286E Ladies' Shop

首先 \(x\in T\) 当且仅当 \(x\) 无法被表示成两个 \(a\) 相加。这个可以通过卷积处理。

然后判断得到的 \(T\) 是否合法,即是否题目中给出的背包 \(A\) 卷上 \(T\) 仍然得到 \(A\)\(0\) 与非 \(0\))意义下,所以仍然卷积处理。

194. CF650E Clockwork Bomb

首先考虑答案的下界为 \(E_1\)\(E_2\) 不相同的边的个数。考虑对于两棵树完全相同的连通块,显然可以直接缩成一个点。之后我们缩完点得到的树,就需要在 \(|V|-1\) 步内转化成另一棵树。考虑两颗树都以 \(1\) 为根,然后每次剥叶子,然后让这个叶子连向自己应该连向的父亲。于是这样也可以保证图每时每刻都是联通的,所以合法。

https://codeforces.com/contest/650/submission/232851078

195. CF571D Campus

离线下来,建出合并的树形结构,并把第一类树的 dfn 作为点的标号。那么问题就变成了子树清 0,然后区间加,求单点。考虑对于每次问询,求出其最后一次清0,那么问题转化为求一段时间内包含这个点的区间加。这是一个二维数点问题。单 log。

196. * CF429E Points and Segments

写一种我最接近的解法:考虑把所有线段按左端点去排序。然后我们注意到前两个线段一定可以一个 0 一个 1。具体而言,若 \(l_1\neq l_2\),那么 \([l_1,l_2)\) 这段区间一定已经合法了,可以直接删去。然后这两个就可以合并,等价于一段 \(r_1,r_2\) 的区间。这样我们就递归到有 \(n-1\) 个区间的子情况了。不断这样合并区间,然后用堆维护所有区间即可。

197. CF274E Mirror Room

我们直接模拟光线的撞墙过程,显然状态数只有 \(O(k)\) 个。我们考虑把坐标轴旋转 45 度,然后每次就相当于问一行中往左右走撞到的第一个格子,或一列中往上下走撞到的第一个格子。然后我们把这些路线记录下来,就变成了 NOI2023D1T1 的严格弱化版本。

* 注:实际上更好的性质,是不存在经过同格且相交的路线。所以就不需要扫描线了,直接统计一下就行了。

198. CF543E Listening to Music

我的 \(O(n\sqrt{n\log n})\) 的做法:首先如果能离线,那么我们把 \(x\) 从小到大排序,维护 \(f\)。那么我们每次相当于需要对 \(a_i=x\) 的位置进行一次区间加,然后问询就是区间取 min。现在强制在线卡空间,考虑对序列分块。对于每一个块,其本质不同的 \(x\) 只有块长个,于是我们对于每个块都过一遍所有操作,然后对于每个这样的 \(x\) 都记录这个块的最小 \(f\),用差分即可做到空间 \(O(B^2)\) 且时间 \(O(n^2/B+B^3)\)。对于散块,我们同时对于每个块记录这个块的整体加的 tag,然后对于每个点,vector记录所有其到块尾的后缀加和其到块头前缀加,然后通过 lowerbound 的方式找出到底应该加多少。单次复杂度 \(O(B\log B)\)。然后询问时需要对对于每个块求出这个 \(x\) 对于这个块相当于什么本质不同的 \(x\),复杂度 \(O(n\log B/B)\)。所以总复杂度 \(O(n\sqrt {n\log n})\)

* 补充:实际上,可以规避半个 \(\log\)。对于第一个 \(\log\),注意到 \(f\) 显然是可以从左到右递推的,所以只需要知道 \(f_l\) 就可以处理出这个块的所有 \(f\)。第二个 \(\log\),考虑实际上不需要记录本质不同的 \(x\),只需要把这些操作按根号分块即可,达到的效果是一样的。

199. CF343E Pumping Station

建出最小割树,于是问题转化为最大化排列两点间路径权值最小值。考虑这个的下界:每条边作为路径上最小值恰好被访问一次。我们找到树上最小权值的边 \(e_0\),于是 \(e_0\) 只能被覆盖一次。于是我们可以把树被 \(e_0\) 劈成两半,我们把两半递归做之后得到的结果可以直接拼起来,拼接处的价值即为 \(e_0\)。不断这样做最终得到一个合法解。

200. CF407E k-d-sequence

首先我们可以拆成若干个模 \(d\) 同余的子段。显然这是几个独立的问题,当成多组数据然后最后合并一下答案即可。然后我们把每个子段全部除以 \(d\) 后,就变成了找到最长的 \([l,r]\) 满足区间内数互不相同且 \(\max-\min\le k+(r-l)\)。我们对 \(r\) 扫描线。对于第一个限制,我们可以双指针求出 \(p_r\) 表示最大的 \(l\) 满足 \([l,r]\) 互不相同。对于第二个限制,我们可以对于每个 \(l\) 维护当前 \([l,r]\)\(s_l=\max-\min-k-(r-l)\)。通过维护两个单调栈,问题即可转化为区间加减以及找到 \([p_r,r]\) 内第一个 \(l\) 满足 \(s_l\le 0\),这个直接线段树上二分即可。