[北大校赛/题解] PKUCPC2023 题解
前言
PKUCPC 2023 的题还是非常有意思的 .
叠个甲 : 因为似乎没地方交题 , 所以只能口胡 , 可能 ( 必定 ) 出锅 .
A. Number Triangle
把每一列看成一个双端队列 , 每个人只能从其中一端取数 .
通过观察能得到结论 : 如果所有列都是偶数长度 , 那么双方肯定都恰好取了其中一半 . 因为如果存在列不是恰好取了其中一半 , 肯定有一方相对于取一半变劣了 , 而且他必然可以修改策略来使得这种情况不会取到 .
奇数长度同理 , 除中间一个之外一人取一半 . 考虑取中间的 , 结论是 : 把所有中间数从大到小排序 , 两个人轮流取 .
考虑先手如果想取到最大的中间数 , 就肯定能在对应的列创造先手条件 , 并做到这一点 ; 同理 , 后手就可以在次大中间数的列创造先手条件 , 以此类推 .
B. Almost Complete Graph
根据题目条件 , 可以猜到这道题的复杂度应该是 \(O(\sum k^2)\) 的 .
哈希的计算方式提示我们整体地计算从点 \(u\) 出发的所有点的距离 . 首先是从 \(u\) 出发有边的点 , 显然最短路就是 \(a_u\) .
考虑 \(u\) 到剩余 \(k_u\) 个点的路径 , 一定是从 \(u\) 出发到一个与 \(u\) 有边的点 \(x\) , 然后路径上的所有点都属于 \(k_u\) 之中 . 证明是如果依次经过与 \(u\) 有边的点 \(x,y\) , 不如直接从 \(u\) 到 \(y\) .
因此先对每个 \(k_u\) 中的点 \(v\) , 求出所有形如 \(u\to x\to v\) 的最短距离 , 然后在 \(k_u\) 个点中跑最短路 .
后半部分的最短路是容易的 , 可以使用暴力 dij , 每次遍历所有点找出还没有更新的 , \(dis\) 最小的点 , 并且对所有其余点尝试更新 , 复杂度是 \(O(k^2)\) 的 .
考虑前半部分 , 要找到存在 \(u\to x\) 和 \(x\to v\) 且 \(a_x\) 最小的 \(x\) . 考虑维护有 \(x\to v\) 的所有 \(x\) 的点集 , 根据抽屉原理 , 只要维护 \(a_x\) 最小的 \(k_u+1\) 个 , 那么至少存在一个满足 \(u\to x\) .
因此对于每个点 \(v\) , 维护 \(sz_v=\max\limits_{u\not\to v} k_u\) 大小的点集 . 总维护量是 $O(\sum k^2) $ 的 , 每次暴力查询即可 , 复杂度也是 \(O(\sum k^2)\) 的 .
要实现这个复杂度还需要实现 \(O(1)\) 检查 \(u\to v\) , 可以用 unordered_set 实现 .
C. Empty up a Bottle
首先发现对 \(a,b\) 操作一次等价于 \(a\gets 2a,b\gets 2b \pmod {a+b}\) .
找一些减量的处理办法 , 如果三个数都是偶数 , 可以约一个 \(2\) , 不影响操作 , 如果存在两个奇数 , 可以操作一下约 \(2\) , 这样每次操作总和折半 .
如果存在三个奇数 , 可以变成两偶一奇 . 发现两偶一奇的情况不能再改变奇偶性 , 需要想新的办法 . 不妨设奇数是 \(a\) 且 \(b>c\) .
发现奇数偶数在一起操作 , 可以通过操作 \(2^{\varphi(a+b)-1}\) 次来等价于偶数 \(\div 2\) . 因此可以设计出组合操作 : 先对 \(b,c\) 操作 \(x\) 次直到不满足 \(b>c\) , 变为\(b+c-2^xc , 2^xc\) , 然后用 \(a,c\) 操作来去掉 \(2^x\) , 变为 \(b+c-2^xc,c\) .
这样可以实现 \(b,c\) 的递减 , 且每次至少折半 , 类似于辗转相除法 . 最后的复杂度是 \(O(\log)\) .
D. Artificial Idiot
可以直接建网格图跑最短路 . 发现点权只有 \(0\) 或 \(1\) , 用双端队列代替优先队列 , 即可 \(O(n)\) 解决 .
E. The Most Beautiful Chicken
根号分治 . 使用最大子段和的思路可以把一个维度变成扫描线 , 但是另一个维度必须要 \(n^2\) 地枚举区间 .
复杂度为 \(\min(n^2m,nm^2)=O(nm\sqrt {nm})\) .
F. Median Plus
题目中已经给了我们单点判断的基本思路 . 假如要验证的位置是第 \(k\) 小 , 值为 \(mid\) , 先贪心地让所有区间都选 \(l\) , 这时 \(l_i\ge mid\) 的部分自然能够贡献 , 然后在 \(r_i\ge mid\) 的部分尽可能选 \(l_i\) 大的 , 这样总和增加的部分 \(mid-l_i\) 就会尽可能小 . 只要能在总和不超过 \(m\) 选出 \(\ge k\) 个点就说明答案 \(\ge mid\) .
考虑使用可持久化线段树维护 \(r_i\ge mid\) 的部分 , 分别查询 \(l_i\ge mid\) 有多少个 , 以及选 \(l_i\) 最大的能选几个 . 可以 \(O(\log)\) 判断 , 总复杂度 \(O(n\log n)\) .
发现问题的复杂之处在于不同的 \(mid\) 对应的 \(r_i\ge mid\) 以及 \(l_i\ge mid\) 的情况也不同 . 考虑对所有值离散化后组成序列 \(b\) , 如果我们确定了第 \(k\) 小的答案就在 \(b_{i-1}\) 和 \(b_i\) 之间 . 那么\(r_i\ge mid\) 的个数 \(cnt1\) 也确定了 , 只需要再取 \(k-cnt1\) 个即可 . 通过线段树可以拿出这些点的 \(\sum l_i\) , 可以 \(O(1)\) 计算出最大的 \(mid\) .
现在只需对每个 \(b_{i-1}\) 到 \(b_i\) 间求出管辖哪些位置 , 可以用类似的手法用线段树得出 .
G. arrays
虽然长得像是 01 规划 , 但是实际上并没有必要 , 因为只取了一个点 , 不需要二分答案 .
直接用李超树维护就可以了 , 因为没有区间限制所以是 \(O(n\log n)\) 的 .
注意线段直接用原来的参数 \(a,b\) 表示就可以 , 不要普通一次函数形式 , 会出浮点数炸精度 .
H. Queens
这题的题面实则不太清晰 , 那个上下边界相邻 , 左右边界相邻 , 可以理解成把每个棋盘四向复制无数份 ( 免费送给世人欣赏口牙 ) , 以扩展出的无限平面上 , 每个棋子不能攻击到除了自己复制出的棋子以外的所有棋子 .
考虑用 \(x+y\) 和 \(x-y\) 表示 \((x,y)\) 占据的两个对角线 , 发现事实上等价于构造 \(0\cdots n-1\) 排列 \(p\) , 使得 \(\{p_i+i\}\) 和 \(\{p_i-i\}\) 对 \(n\) 取模下都是排列 .
结论是 \(p_n\) 合法当且仅当 \(p_n\) 是同余意义下的等差数列 , 且公差 \(k-1,k,k+1\) 都与 \(n\) 互质 .
可以使用归纳法证明 .
也就是只要 \(2\not\mid n\) 且 \(3\not\mid n\) 即可 , 构造公差 \(k=2\) 就行 .
I. Rhode Island Dormitory Allocation Problem
如果没有环的话 , 肯定是排序后位置一一对应 .
考虑有环 , 相当于把所有位置轮换一遍 , 然后一一对应 .
第一种解法就是直接维护每个值的贡献 , 总共有 4 种情况 , 而且每个轮回一遍过程中最多切换 4次 , 直接维护就可以 \(O(n)\) .
第二种是等价模型 , 在没有环时 , 求出 \(s_i=\sum_{j<i} a_j-b_j\) , 其中 \(a,b\) 表示一个位置上人的个数和空位的个数 , 这表示有多少人要走过 \(i\) 这一位置 , 答案即 \(\sum |s_i|\) .
在有环时 , \(1\) 和 \(n\) 位置之间可以互通 , 所以相当于对所有 \(s_i\) 全局加 \(t\) , 令 \(-t\) 取中位数即可最优化 .
还有一个唐氏做法 , 发现如果在合适的地方断开 , \(m\) 种轮换的答案构成单峰函数/单谷函数 , 但是也可能呈现出一峰一谷 , 发现递增段和递减段似乎都是 \(\frac{m}{2}\) 长度的 , 所以从中间断开就是单峰函数/单谷函数 ,可以二分/三分解决 .
J. Hat Puzzle
题意有点模糊 . 这里指第 \(i\) 个人能看到 \(2\cdots i-1\) 的人的帽子 .
结论 : 所有看到的帽子两种颜色个数不同的人都能猜到 .
首先看到的两种颜色个数相同的人不论得到什么信息 , 都不能确定自己的颜色 .
考虑连续的一段看到的帽子两种颜色个数不同的人 , 他们发现上一个人一直没有确定 , 就可以知道最近的两个颜色帽子相同的前缀 , 就可以推测出自己的颜色与自己看到中较小的那一个相同 . 因为直到下一次有人不确定 , 两个颜色的大小关系是确定的 , 因此连续段内所有人都能推出来 .
K. Crafting materials
发现值域为 \(1000\) 很小 , 哪怕全部push到一层也不会超过 \(2000\) , 所以可以直接 \(O(nm^2)\) dp , 状态是 \(f_{i,j,k}\) 表示第 \(i\) 层剩 \(j\) 个, 当前层已经push玩的能向第 \(i+1\) 层提供 \(k\) 个的成功率 , 直接 dp .
L. Lawn naming
签到题 , 二分答案 .
M. Center of a Tree
注意到树的重心的一般定义 ( 子树大小不超过 \(\frac{N}{2}\) ) , 实际上决定了不管把重心往哪个方向移动 \(\sum dis\) 都会变大 , 因此事实上重心位置和边权无关 .
我们直接把这棵树建出来 , 并且维护 1 或 2 个重心 , 改边权操作事实上不会影响到重心位置 , 加点操作最多让重心影响一步 . 且每一次修改或者移动重心最多考虑一条边的贡献发生了变换 , 只需用子树和维护有多少点算上了这条边即可 .
用数据结构维护即可 .

浙公网安备 33010602011771号