ICPC2025 上海区域赛题解
经典战役回顾。。。
其实每一道单独拿出来都是很不错的题目,但是这样组题就很坏了。
网上几乎找不到这场比赛的题解,只能对着官方题解(感觉 thu 的 ppt 不是很题解,更像是博客上的口胡)生啃。
D Not a subset sum
这就是 thu 的签到。
把 ? 当成 2,于是是三进制数。
按照高维前缀和的思想,不难想到将 \(0\) 和 \(1\) 的答案汇集到 \(2\) 上。
这样复杂度是 \(O(3^n \times 16)\) 的,与暴力无异。
但是只有为 \(2\) 的数会被更新,所以可以除掉一个 \(3\) 的常数,在 qoj 上可以极限通过。
仔细推敲,发现很多状态是空的,具体地,只有当这个 \(2\) 是最高位的时候才会有贡献。
所以可以枚举最高位 \(2\) 的位置,然后枚举左侧(是个二进制数)和右侧(是个三进制数)。
这个被拼起来的数的答案,就是最高位 \(2\) 改写成 \(0\) 和 \(1\) 的答案加起来。
时间复杂度 \(O(\sum 2^i 3^{n-i})=O(3^n)\)。
AC代码。
H AGI
很 cf 味道的好题。
首先对一样的数进行分组,不难意识到一定会被尽量均分(因为先后手都可以强迫制造均分的局面,无论这个数能否被取到,一定对某方是最优的)。
出现数量为偶数的数直接算上异或意义的贡献即可。
出现数量为奇数的数会多出来一个。如果出现数量为奇数的数的数量 \(> 2\),不难得出先手一定会败(归纳到剩三个数的时候,后手一定能制造先手败的局面)。否则只会多出来两个数,检查先手是否有取之后异或和为 \(0\) 的即可。
AC代码。
G Gemcrate
也是兼具算法和思维的好题。
结论:一定不会分 \(\geq 3\) 组。证明:如果某种选法的某位是 \(1\),那么选 \(3\) 组并为 \(1\) 组一定不劣,因为 \(1\) 不会变成 \(0\) 而 \(0\) 有概率变成 \(1\)。
因此根据最高位 \(1\) 的数量进行贪心:
如果数量为奇数,直接分为 \(1\) 组。
如果数量为偶数,必须分为 \(2\) 组。对于 \(1\) 的数量为奇数的某位,这一位一定取不到,把所有数的这一位变成 \(0\)。这样处理之后所有数的异或和为 \(0\),分出的两组数异或和一定相同。全部扔进线性基里,求一个最大异或和就是答案。
AC代码。
J Yet another mailbox problem
这个倒是较为无趣的题目。
代码是很久以前写的。
注意到边权很小(\(\leq 8\))。容易想到在 trie 树上 dfs。
初始先将所有边加入 trie 树,然后由小往大,dfs 的过程中顺便加点,访问了 \(k\) 条路径之后直接结束程序。
时间复杂度 \(O(n+k)\)。
AC代码。
A Menji, we miss you!
先用 \(logn\) 次问出答案的深度。
考虑每次排除一些点,思考重心是一个合理且传统的方向。
这又是二叉树,因此去除重心后只会有至多三个连通块,并且 \(\frac{n}{3} \leq\) 最大的连通块大小 \(\leq \frac{n}{2}\)。
而这个最大的连通块,要么是重心的重儿子方向,要么是重心的父亲方向。
每次询问重心的重儿子,如果父亲方向是最大的连通块,会排除至少 \(\frac{n}{2}\) 个点。如果重儿子方向是最大的连通块,会排除至少 \(\frac{n}{3}\) 个点。
于是至多只要 \(logn+log_{\frac{3}{2}}n\) 次交互就可以求出答案。
反正只有 \(40\) 次,每次暴力删点找重心就行。
AC代码。
B Hamu
构造题,考虑先约束住大的范围。
最后的结果符合所有点的异或和为 \(0\),而在二分图中走出的都是偶环,无法改变整体的异或和,因此此时无解。
不然我们先走一个奇环(奇环在判的时候能顺便找到,染色的体现是一棵颜色交替的生成树),将所有点的异或和改为 \(0\)。
这个时候再随便走一棵生成树,如果回溯时 \(a_u\) 为 \(1\),那就再往返一遍去父亲的边。
这保证了除根外每个点的结果都是 \(0\),而因为总异或和为 \(0\) 也锚定了根的值为 \(0\)。(走出来的一定是个偶环)。
复杂度 \(O(n+m)\)。
AC代码。
I Round screws
每个数可以任意改,改成和上一个数相同一定是最优的。因为 \(x \oplus y + y \oplus z \geq x \oplus z\)。
所以考虑保留哪些数,设计出一个 \(O(n^2)\) 的 dp,\(dp_i\) 表示考虑 \(1 \sim i\) 保留第 \(i\) 个数的最小代价。
则 \(dp_i = \min\limits_{j<i} dp_j+(i-j-1)\times C+a_i \oplus a_j\)。
很难再优化,但是值域并不大,分离变量后可以将复杂度瓶颈转到值域上去。
记 \(g_v\) 是 \(\min\limits_{a_j=v} {dp_j-j\times C}\),转移可以变成 \(O(nV)\) 的 \(dp_i = \min\limits_{v} g_v+(i-1)\times C+a_i \oplus v\)。
仍然不够,继续优化,考虑将 \(2^{18}\) 分为高 \(9\) 位和低 \(9\) 位。
设 \(\frac{高位数}{2^9}\) 为 \(H\),低位数为 \(L\)。\(a_i\) 的\(\frac{高位数}{2^9}\) 为 \(h\),低位数为 \(l\)。
那么转移可以写成 \(dp_i=(i-1)C + \min\limits_{H,L} [g_{2^9H+L}+2^9(h \oplus H)+(l \oplus L)]\)。
我们不能够同时枚举 \(H\) 和 \(L\),一定是枚举一个量并将另一个量约束起来。
如果枚举 \(H\),\(h \oplus H\) 是固定的,约束的目的是解决 \(l \oplus L\) 这一项。
因此设 \(g1_{H,L}\) 表示 \(g_{2^9H+L}\),\(g2_{H,K}\) 表示 \(\min \limits_{L}(g1_{H,L}+L\oplus K)\)。
于是能将 \(dp\) 写成 \(O(n \times 2^9)\) 的转移:\(dp_i=(i-1)C + \min\limits_{H} [2^9(h \oplus H)+g2_{H,l}]\),枚举 \(H\) 即可。
每次转移完只会更改 \(g1_{h,l}\) 的值,只会对 \(g2_{h,K}\) 有贡献,单次也是 \(O(2^9)\) 的。
于是总复杂度 \(O(n \times 2^9)\)。
官方题解本质上应该是一样的东西,但是没能很看懂。
AC代码。
K No more regrets
好 oi 的题目。
这里是线段树的做法,前置知识是单侧递归线段树。
回忆一下经典的在线段树上维护 \(\sum \limits_{j=L}^R \max \limits_{i=L}^j a_i\) 的问题。
信息合并的时候左儿子可以直接加上,而右儿子需要和左儿子的最大值取个 \(\text{max}\)。
设计出一个 \(\text{compute}(u,mx)\) 函数,表示线段树上 \(u\) 号节点和 \(mx\) 取较大值后的答案。
如果左儿子最大值 \(\leq mx\),左儿子被推平,递归右儿子;反之递归左儿子,而右儿子的信息就是原始“左对右”的贡献(\(smx_u-smx_{u<<1}\))。
每次只会往一侧走,所以 \(\text{compute}\) 和线段树二分的复杂度一致,是 \(O(logn)\) 的。
回到此题的 \(\sum \limits_{j=L}^R \max \limits_{i=L}^j a_i \times \min \limits_{i=L}^j a_i\),可以仿写出 \(\text{compute}(u,mx,mn)\) 函数,表示线段树上 \(u\) 号节点对 \(mx\) 取 \(\text{max}\),\(mn\) 取 \(\text{min}\) 的答案。
设左儿子 \(\text{max}\) 为 \(lmx\),\(\text{min}\) 为 \(lmn\)。
分为四种情况:
若 \(lmn \geq mn, lmx \leq mx\),左子树直接被推平,递归右儿子即可;
若 \(lmn \leq mn, lmx \geq mx\),递归左儿子,加上“左对右”的影响即可;
若 \(lmn \geq mn, lmx > mx\),左子树的最小值被推平,做一次只对最大值的 \(\text{compute}\),再递归右儿子即可;
若 \(lmn \leq mn, lmx < mx\),左子树的最大值被推平,做一次只对最小值的 \(\text{compute}\),再递归右儿子即可;
只会遍历 \(O(logn)\) 个节点,每个节点可能做一次只对最小/大值的 \(\text{compute}\),所以 \(\text{compute}\) 复杂度是 \(O(log^2n)\) 的。
线段树的修改查询也只会遍历 \(O(logn)\) 个节点,因此总复杂度是 \(O(nlog^3n)\) 的。

浙公网安备 33010602011771号