ABC396 EFG 题解
ABC396 EFG 题解
E
套路性地想到通过图来描述约束关系:构造一个 \(n\) 个节点的图分别表示 \(a_{1} \sim a_{n}\),如果存在一个限制 \((x, y, z)\) 表示 \(a_{x} \oplus a_{y} = z\),就在 \(x\) 和 \(y\) 之间连一条边权为 \(z\) 的边。
不妨假设图连通。如果不连通,则分别计算各个连通块的答案再累加。
处理位运算问题的经典套路是逐位考虑,因为位运算的一个优良性质是各比特位之间互不影响。不妨假设所有边权都为 \(0\) 或者 \(1\),也就是只有一个比特位。那么,钦定图中任意一点的点权,则其它点的点权也可以唯一确定。并且,由于异或的性质,如果钦定某个点 \(u\) 的点权为 \(0\) 时,图中没有矛盾,那么把 \(u\) 的点权设为 \(1\),其它点的点权也必须跟着取反,仍然没有矛盾。由于位运算之间各个位互不影响,所以这个结论可以直接拓展到边权不止一个比特位的情况。也就是说,一个图要么没有合法方案,要么可以把一个点的点权任意赋值(而其它点的点权由此推出),得到无数个合法方案。
不妨假设图有合法的赋点权方案,最后考虑如何令点权和最小。先给图中一个点随便设一个点权,得到一个任意的合法方案。然后还是逐位考虑。对于一个比特位,分别统计图中有多少点的点权中该位为 \(1\) 和 \(0\)。如果 \(1\) 的个数少于 \(0\),则无需改变;否则每个点的点权中这一位都取反,得到的方案仍然合法,但是点权和变小了。
设 \(w = \max a_{i}\),则总时间复杂度为 \(O(m + n \log w)\)。
F
对 \(A\) 数组全局 \(+1\) 就相当于对 \(B\) 数组全局 \(+1\),然后把一些位置变成 \(0\)。具体而言,数 \(x\) 会在第 \((M - x)\) 轮变成 \(0\)。先求出没有修改时全局逆序对数,然后只需考虑每一轮变成 \(0\) 的数对逆序对数量的影响。
由于 \(0\) 是数组中的最小值,而一开始不等于 \(x\) 的数在第 \((M - x)\) 轮一定不为 \(0\),所以可以枚举数组中所有为 \(0\) 的位置,统计以它开头的逆序对数量,这就是第 \((M - x)\) 轮新增的逆序对数。而这些 \(0\) 在上一轮一定是 \(M - 1\),是数组中的最大值,因此还要减去以它们结尾的逆序对数,仍然枚举上一轮所有的 \(M - 1\) 即可。
由于每个数只有 \(1\) 次会变成 \(0\),所以枚举的总时间复杂度为 \(O(n)\)。
G
这道题用 FWT 似乎更加直接,可惜我目前不会。本文的做法和官方题解相同,都是使用 dp。(但不得不吐槽官方题解讲的实在太过于抽象,有的式子甚至打错了,所以你也可以把这篇题解看作是官方题解的人话翻译)
下文把题目中的 \(H\) 和 \(W\) 分别记为 \(n\) 和 \(m\)。
首先发现 \(m\) 很小,这肯定是我们的切入点。如果确定了有哪些列要翻转,那么显然就可以逐行计算答案。不妨把列的翻转状态看作一个 \(m\) 位二进制数 \(s\),第 \(i\) 位为 \(1\) 表示翻转第 \(i\) 列,否则表示不翻转。对于每一列,也把它的状态记为 \(m\) 位二进制数,第 \(i\) 行记为 \(b_{i}\)。
那么,如果列的翻转状态为 \(s\),则第 \(i\) 行翻转后的状态就是 \(b_{i} \oplus s\)。此时如果不翻转第 \(i\) 行,则有 \(\operatorname{popcount}(b_{i} \oplus s)\) 个 \(1\),否则有 \((m - \operatorname{popcount}(b_{i} \oplus s))\) 个 \(1\)。也就是说答案为
如果暴力枚举所有 \(2^{m}\) 种列的翻转状态,总时间复杂度就为 \(O(2^{m}n)\),无法接受。
考虑用 dp 优化求解的过程(本质上是信息复用)。如何设计状态呢?直接设 \(f(s)\) 表示翻转状态为 \(s\) 时的答案肯定是不可行的,因为没有给出任何额外信息。不妨设 \(f(s, i)\) 表示有多少行 \(j\) 满足 \(b_{j}\) 和 \(s\) 有 \(i\) 位不同。这实际上代表着 \(\operatorname{popcount}(b_{j} \oplus s) = i\),因此翻转列之后第 \(j\) 行有 \(i\) 个 \(1\)。于是答案为
但这样还是不能转移。于是我们强制多设一维状态:设 \(f(s, t, i)\) 表示有多少行 \(j\) 的最低 \(t\) 位和 \(s\) 的最低 \(t\) 位有 \(i\) 位不同,而前 \((m - t)\) 位全相同。这样设是为了能够逐位转移。转移到第 \(m\) 位的时候,就可以用来统计答案了,因为此时不再要求和 \(s\) 的某个前缀相同。
初始化 \(\forall 1 \le i \le n\),\(f(b_{i}, 0, 0) \gets f(b_{i}, 0, 0) + 1\)。
转移:
这是讨论了两种情况:如果有一行 \(j\),它只在最后 \(t\) 位和 \(s\) 不同,且不同的位数为 \(i\),那么要么第 \(t\) 位和 \(s\) 相同,这样的行有 \(f(s, t - 1, i)\) 个;要么第 \(t\) 位和 \(s\) 不同,这样的行有 \(f(s \oplus 2^{t}, t - 1, i - 1)\) 个。
dp 的状态数为 \(O(2^{m} m^{2})\),转移的时间复杂度为 \(O(1)\),所以总时间复杂度为 \(O(2^{m} m^{2})\)。