「loj - 2850」「ROI 2018 Day 2」无进位加法
以前以为自己会证时间复杂度,后来考到原题发现自己证伪了,草。
从高到低确定 \(\sum b\) 的每一位是否可以为 \(0\)。
枚举第 \(p\) 位是否可以为 \(0\) 时,比第 \(p\) 位低的位全部填 \(1\),比第 \(p\) 位高的保留不变,得到一个 \(\sum b\)。之后看是否存在一个 \(\{b_i\}\) 满足要求。
相当于我们需要把 \(\sum b\) 的每个 \(1\) 分配给某个 \(i\)(也即,\(b_i\) 的这一位为 \(1\)),使得 \(a_i\leq b_i\)。
简单的观察:不妨设 \(a_1\geq a_2 \geq \dots \geq a_n\),则存在一个最优解满足 \(b_1 \geq b_2 \geq \dots \geq b_n\)。
由观察,考虑 \(\sum b\) 最高位的 \(1\),它一定分配给最大的 \(a_{max}\)。
如果 \(\sum b\) 的最高位 \(h\) 大于 \(a_{max}\) 的最高位 \(q\),则 \(a_{max}\) 接下来不需要被分配其他的 \(1\),直接删掉。
如果 \(\sum b\) 的最高位 \(h\) 等于 \(a_{max}\) 的最高位 \(q\),则需要把 \(a_{max}\) 删去最高位后再塞回去(如果删掉最高位后非零的话)。
如果 \(\sum b\) 的最高位 \(h\) 小于 \(a_{max}\) 的最高位 \(q\),则不合法,此时 \(\sum b\) 的第 \(p\) 位填 \(0\)。
当然,如果把所有 \(a\) 都删完了,则 \(\sum b\) 的第 \(p\) 位填 \(1\)。
显然,这一过程不需要每次都从最高位开始扫 \(\sum b\),比 \(p\) 高的位的影响保留下来,可以从第 \(p - 1\) 位开始往后扫。
某时刻的某个 \(a\) 一定是初始时的某个 \(a_i\) 删去最高的若干个 \(1\) 的情况,因此在过程中 \(a\) 的可能情况只有 \(O(\sum L)\) 种。
可以将这 \(O(\sum L)\) 种可能的 \(a\) 拿出来排序,具体来说由于只有长度相同的需要排,做个基数排序即可(当然,由于这部分不是瓶颈,你也可以尝试一些 \(O((\sum L)\log(\sum L))\) 的排法)。
考虑某一时刻枚举到 \(\sum b\) 的第 \(p\) 位。
设此时 \(a_1\geq a_2 \geq \dots \geq a_n\),并设 \(a_i\) 的最高位为 \(t_i\)。则合法的一个必要条件为 \(\forall i,p - i\geq t_i\)。
分配给 \(a_i\) 的 \(1\) 最大也只能是 \(p - i\),还有可能因为前面的数需要删去最高位重新塞回来而变小。
另一方面,合法的一个充分条件为 \(\forall i, p - i > t_i\)。
此时所有数都可以直接被删掉。
那么事实上需要检验的只有 \(p = \max\{i + t_i\}\) 的情况。
我们找到使得 \(i + t_i\) 最大的 \(i\) 中最小的 \(k = \min\{i\}\)。
如果 \(p = \max\{i + t_i\}\) 填 \(0\),则 \(a_1\sim a_k\) 分别对应了 \(\sum b\) 的第 \(p - 1 \sim p - k\) 位上有 \(1\)。
删掉 \(a_1\sim a_k\),插入 \(a_k\) 删去最高位后的 \(a'_k\),然后继续找 \(p' = \max\{i + t_i\}\)。
如果 \(p - k > p'\),则前面的合法。
如果 \(p - k < p'\),则前面的不合法。
如果 \(p - k = p'\),我们令 \(p = p'\),令 \(k\) 为此时使得 \(i + t_i\) 最大的最小 \(i\),然后继续递归检验。
可以使用线段树维护查找最大值的过程。
然后可以证明,这样递归的总次数不会超过 \(O(\sum L)\)。由于使用线段树维护,总复杂度为 \(O(\sum L\log(\sum L))\)。
首先,相同长度的 \(a_i\) 只会有一个最大的 \(i + t_i\)。也即,我们每次选定的 \(a_{k'}\) 比上次递归进来的 \(a_k\) 对应的长度要短。
因此,如果最开始需要检验的是 \(p\),则递归次数实际上不会超过 \(O(L_p)\)。
而对于每个串,它只有一次是“最开始”检验的。因此得证。