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)\) 的。

AC 代码

posted @ 2026-03-29 00:23  c0Sai  阅读(918)  评论(0)    收藏  举报