Codeforces Round 954 (Div. 3)
A. X Axis
- 给定 \(x_1, x_2, x_3\)。求 \(\min_i \sum_j |x_j-i|\)。
显然排序后取中位数。
B. Matrix Stabilization
- 给定 \(n \times m\) 的矩阵 \(a_{i,j}\)。每次操作找到一个 \(i\) 最小的前提下 \(j\) 最小的,满足 \(a_{i,j}\) 严格大于所有与它相邻的值的 \((i, j)\),并将 \(a_{i,j} \gets a_{i,j} - 1\)。输出不能操作时的矩阵。
- \(n, m \le 100\),\(n \cdot m > 1\),\(1 \le a_{i,j} \le 10^9\)。
说明:
- 以下分析复杂度时认为 \(n, m\) 同阶。
- 为方便表述,我们定义下标的不等关系为(其余不等关系 \(>, \le, \ge\) 的定义类比):
- 定义「操作 \((i, j)\)」为 \(a_{i,j} \gets a_{i,j} - 1\)。
- 与 \((i, j)\) 相邻的位置可能会有 \(1, 2, 3, 4\) 个。方便起见我们在 \(a\) 的上下左右分别用 \(0\) 填满。这样就一定是 \(4\) 个了。
暴力做法显然会爆炸。例如当 \(a = \begin{Bmatrix} 1 & 10^9 \end{Bmatrix}\) 时我们会将 \(a_{1,2}\) 操作 \(10^9\) 次。
进一步观察发现,如果 \((i, j)\) 是满足「大于所有与它相邻的值」的,那么接下来会「操作 \((i, j)\)」若干次,直到 \(a_{i,j}\) 不满足「大于所有与它相邻的值」,也就是成为这些值中的最大值。
此时你就有了一个 \(\mathcal O(n^4)\) 的做法:执行至多 \(\mathcal O(n^2)\) 次,每次以 \(\mathcal O(n^2)\) 的复杂度找到这个 \((i, j)\),然后 \(\mathcal O(1)\) 修改。
考虑如何优化复杂度。如果我们称「『操作 \((i, j)\)』若干次直到 \(a_{i,j}\) 不满足『大于所有与它相邻的值』」为一轮操作,事实上,如果这一轮操作 \((i, j)\),那么下一轮操作的 \((i', j')\) 一定满足 \((i, j) < (i', j')\)。换言之,你只需要从上一轮找到的 \((i, j)\) 开始往后找新一轮的 \((i', j')\) 即可。
考虑证明。
实际上我们需要证明两件事情:
- 如果 \((i, j)\) 是满足「大于所有与它相邻的值」的,那么接下来会「操作 \((i, j)\)」若干次,直到 \(a_{i,j}\) 不满足「大于所有与它相邻的值」,也就是成为这些值中的最大值。
- 如果这一轮操作 \((i, j)\),那么下一轮操作的 \((i', j')\) 一定满足 \((i, j) < (i', j')\)。
显然这两个命题可以合并成:
- 如果这一次操作 \((i, j)\),那么下一次操作的 \((i', j')\) 一定满足 \((i, j) \le (i', j')\)。
考虑反证法。证明:
- 如果这一次操作 \((i, j)\),那么下一次操作的 \((i', j')\) 可能满足 \((i, j) > (i', j')\)。
是伪的。
分类讨论。以下讨论的前提都是 \((i, j) > (i', j')\):
- \((i', j'),(i, j)\) 相邻:那么操作 \((i', j')\) 后一定有 \(a_{i',j'} = \max(a_{i'-1,j'}, a_{i',j'-1}, a_{i', j'+1}, a_{i'+1,j}) \ge a_{i, j}\)。此时显然无法「操作 \((i, j)\)」,因为 \((i', j')\) 就是一个与 \((i,j )\) 相邻的且不大于 \(a_{i, j}\) 的位置。因此矛盾。
- \((i', j'), (i, j)\) 不相邻:如果「操作 \((i, j)\)」后可以「操作 \((i', j')\)」,那么「操作 \((i, j)\)」前也一定可以「操作 \((i', j')\)」。所以上一步一定是「操作 \((i', j')\)」而不是「操作 \((i, j)\)」,这是因为 \((i', j') < (i, j)\)。因此矛盾。
综上,原命题得证。
C. Update Queries
- 给定长度为 \(n\) 的字符串 \(s\) 和长度为 \(m\) 的数组 \(ind_i\) 和一个长度为 \(m\) 的字符串 \(c\)。你可以将 \(ind\) 和 \(c\) 打乱顺序,然后依次按照 \(i = (1, 2, \dots, m)\) 执行 \(s_{ind_{i}} \gets c_i\)。求最后得到的字典序小的 \(s\)。
- \(n, m \le 10^5\)。
显然贪心。发现 \(ind\) 中值 \(i\) 的出现次数是不重要的,我们只需要关注这个值是否出现。若 \(i\) 没出现那么一定仍保持 \(s_i\) 不变,否则一定是将 \(c\) 排序后,按 \(i, j\) 递增的顺序执行 \(s_i \gets c_j\)。
D. Mathematical Problem
- 给定一个长度为 \(n\) 的数字串。你需要在 \(n - 1\) 个空中选择 \(n - 2\) 个空插入运算符 \(+\) 或 \(\times\)。求表达式的最小值。
- \(t \le 10^4\),\(n \le 20\)。
显然 \(\mathcal O(n)\) 枚举哪个空不放运算符。然后就可以得到总共的 \(n - 1\) 个数字。
显然 DP。设 \(f(i)\) 表示前 \(i\) 个数字构成的表达式的最小值。转移可以枚举 \(j\) 表示最后一个加号在 \([j - 1, j]\) 之间。即:
E. Beautiful Array
- 给定长度为 \(n\) 的数组 \(a_i\) 和一个整数 \(k\)。你可以重新排列 \(a\) 使得将 \(a\) 成回文串的所需操作次数最少。定义一次操作为将任意 \(a_i \gets a_i + k\)。
- \(n \le 10^5\),\(k, a_i \le 10^9\)。
考虑若只有两个数 \(x, y\),每次可以选择一个数将其加 \(k\),最少需要几步。
不难发现 \(x, y\) 加上无论多少倍的 \(k\) 后,在模 \(k\) 意义下的值一定是不变的。所以若最开始 \(x \not\equiv y \pmod y\) 那么无解。
否则,若 \(x \equiv y \pmod k\),此时最优方案一定是把 \(x, y\) 中的较小值累加到较大值。即最少需 \(\dfrac{|x-y|}k\) 步。
考虑 \(n\) 个数的情况。若 \(n\) 为偶数,那么我们相当于从中选出 \(\dfrac n2\) 对数,然后按照上面操作每对数。否则,若 \(n\) 为奇数,那么首先要选出一个数放在中间位置,剩下的 \(n - 1\) 个数按照偶数的操作。
先考虑偶数。我们可以统计出每个在模 \(k\) 意义下相同的数构成的集合,用 vector 存储。此时就可以对于每个 vector 单独考虑两两组对的情况(因为不同 vector 中的数 \(\bmod k\) 一定不同,根据前文所述一定不合法)。即:
给定一个数组 \(b_i\)。将这些数两两配对,使两个数的差的绝对值之和最小。
注意这里我们没有考虑 \(\dfrac 1k\) 的影响。因为我们只需要将这个公因式最后乘即可。
令 \(m = |b|\)。显然 \(m\) 为奇数时一定无解。否则一定是将 \(b\) 排序后相邻两个组成一对,即答案 \(\sum (-1)^ib_i\)。
若 \(n\) 为奇数,那么我们需要找到一个长度为奇数的 vector,然后选择其中的一个放在 \(a\) 的最中间,然后剩下的按照偶数的处理。注意这里如果存在两个及以上长度为奇数的 vector 那么无解。现在的问题是:
给定一个长为奇数的数组 \(b_i\)。删除一个数后,将这些数两两配对,使两个数的差的绝对值之和最小。
若删除的数是 \(b_i\),那么此时的答案应为 \(\sum_{j=1}^i (-1)^jb_j + \sum_{j=i+1}^n (-1)^{j+1}b_j = \sum_{j=1}^i (-1)^jb_j - \sum_{j=i+1}^n (-1)^jb_j\)。预处理前后缀即可。
F. Non-academic Problem
- 给定 \(n\) 个点 \(m\) 条边的简单无向连通图。你需要删除一条边使得图中连通的顶点对 \(1 \le u \le v \le n\) 最少。求这个最小值。
- \(n, m \le 10^5\)。
显然删除一个 e-dcc 中的点一定是不优的,因为这样不会连通的顶点对不会减少。
所以将 e-dcc 缩点,每个点的点权为其代表的 e-dcc 中的点数。因为原图连通所以形成了一颗树。我们考虑删除一条树边带来的收益。
若令这条边为 \((u, v)\),那么原本连通现在不连通的顶点对数,应该是从 \(u\) 出发不通过 \(v\) 能到达的节点数,与从 \(v\) 出发不通过 \(u\) 能到达的节点数的乘积。预处理子树和即可。