「loj

link。

以前以为自己会证时间复杂度,后来考到原题发现自己证伪了,草。


从高到低确定 (sum b) 的每一位是否可以为 (0)

枚举第 (p) 位是否可以为 (0) 时,比第 (p) 位低的位全部填 (1),比第 (p) 位高的保留不变,得到一个 (sum b)。之后看是否存在一个 ({b_i}) 满足要求。

相当于我们需要把 (sum b) 的每个 (1) 分配给某个 (i)(也即,(b_i) 的这一位为 (1)),使得 (a_ileq b_i)

简单的观察:不妨设 (a_1geq 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_1geq a_2 geq dots geq a_n),并设 (a_i) 的最高位为 (t_i)。则合法的一个必要条件(forall i,p - igeq 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_1sim a_k) 分别对应了 (sum b) 的第 (p - 1 sim p - k) 位上有 (1)

删掉 (a_1sim 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 Llog(sum L)))

首先,相同长度的 (a_i) 只会有一个最大的 (i + t_i)。也即,我们每次选定的 (a_{k'}) 比上次递归进来的 (a_k) 对应的长度要短。

因此,如果最开始需要检验的是 (p),则递归次数实际上不会超过 (O(L_p))

而对于每个串,它只有一次是“最开始”检验的。因此得证。

原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/14852435.html