「HCOI-R1」孤独的 sxz 题解

· · 题解

几个挺有意思的解法。

题意简述

给定一个 n\times m 的表格,上面有 k 个格子被涂黑了。求一个白色格子,到所有黑色格子的曼哈顿距离之和最大n, m\leq 10^9, k\leq 4\times 10^5

主要思路

若没有 n, m 的限制,答案是无限大的,选一个特别远的点即可。所以自然地想到,加上 n, m 的限制,应当尽量选边角上的点。

为啥呢?不妨先钦定选择的点在第 x 行。那么纵坐标的贡献对这一行都是相等的。那么问题变成一维的,数轴上若干个点,离他们距离和最远的点,要么是最右的点,要么是最左的点,这个很显然。所以对于每一行,答案要么是最左边那个白点,要么是最右边那个白点。对列可以类似地分析。我们称这种最左/右的点为关键点。

解法一

直接暴力做即可,复杂度 O(k\sqrt k)

枚举行,若这一行最左边的白点比前面所有行最左边的白点都更左,那么它有可能成为答案。求出一行最左边的点可以 O(l\log k),其中 l 是最左边的点的横坐标。所以求出所有行有贡献最左边点的复杂度为 O(\log k\sum l) = O(k\log k)。也可以这么理解:每个黑点最多只被遍历一次,所以总复杂度 O(k\log k)

注意到,一个横坐标为 x 的关键点,前面一定有 x - 1 个黑点作为支撑。并且按行看,没有横坐标相同的靠左的关键点。由于 1 + 2 + 3 + \dots + n = O(n^2),且 \sum_{p\in \{\text{关键点}\}} p_x \leq k,极端情况下,p_x 就是 1..n 的形式。所以关键点的个数是 O(\sqrt k) 级别的。

这是个很经典的结论。例题:喵星球上的点名。

所以直接暴力 O(k) 计算每个关键点的答案即可。总复杂度 O(k\log k + k\sqrt k) = O(k\sqrt k),思路极简单,代码也好写

下面是两段比较关键的代码。

这个做法复杂度比较高,不过出题人没有卡。我造了组极限数据,这种做法要跑 900 ms,也确实能过。

解法二

不同于解法一,我们考虑如何优化计算,给定一个白点 $(a, b)$,其到所有曼哈顿距离之和。 这有个板子题,是 Gym100739E Life as a monster。 首先横纵坐标的贡献可以拆开算。就拿横坐标来说,将所有黑点分类成 $L = \{x\mid x \leq a\}$ 和 $R = \{x\mid x > a\}$ 两种。那么答案是: $$ \left(|L|\cdot a - \sum_{i\in L} i\right) + \left(-|R|\cdot a + \sum_{i\in R}i \right) $$ 可以离散化后,前缀和计算这个答案。带修可以树状数组,强制在线就平衡树。本题前缀和即可。 枚举所有白点计算答案肯定是不行的。还是可以用一下**主要思路**中提到的结论,不过我们不需要那么麻烦。注意到所有关键点(除了四个角)一定和某个黑点相邻。所以枚举黑点相邻的点即可。最后如果四个角有白色的,加上这些的贡献即可。复杂度 $O(k\log k)$,瓶颈为离散化。 代码也很好写,我就不放了。 其实在此基础上,我们发现并不需要离散化这个步骤,只需要排序(扫描线)。比如就拿横坐标贡献来说。将所有点按照横坐标升序排序,从左到右遍历每个黑点,计算当前前缀和即可。总复杂度 $O(k\log k)$。 ### 解法三 $O(k)$。 在解法一的基础上,进一步地,可以发现每个关键点离边界较大的距离不超过 $k$。这个可以从求解关键点的过程的复杂度得到。 所以,在解法二的基础上,我们只需要对横坐标小于等于 $k$ 的点计数排序(或开个桶前缀和)即可。只用遍历离边界不超过 $k$ 的黑点,剩下的点一定在关键点的另一侧,可以 $O(1)$ 计算贡献。总复杂度 $O(k)$。