CF1693F I Might Be Wrong 题解
感觉是一个比较套路的题目。
思路
很容易就可以胡出一个贪心策略。
每一次操作都选一个从前面开始最长的 \(0,1\) 数量相同的序列进行操作。
看一眼好像样例都能过。
可以考虑如何来证明一下这个东西。
为了方便,首先我们假定操作序列中 \(0\) 的数量多于 \(1\) 的数量。
那么我们的操作就是要将所有在 \(1\) 中的 \(0\) 全部都移到左边。
很显然,我们的操作的每一段要么是 \(0\) 的数量多于 \(1\) 的数量,或者是 \(0\) 的数量等于 \(1\) 的数量(因为 \(0\) 的数量少于 \(1\) 的数量显然不优)。
当 \(0\) 的数量多于 \(1\) 的数量时。
整体所需要耗费的代价也就是 \(0\) 的数量多于 \(1\) 的数量的值,再加一。
我们将 \(0\) 的数量多于 \(1\) 的数量的值设为 \(k\)。
那么,同样的,我们可以将此时的操作序列中进行 \(k\) 次在一个前缀满足 \(0\) 的数量等于 \(1\) 的数量的序列上进行操作,可以观察到,每一次操作后,至少会有一个 \(0\) 被移到左边,而每一次的代价均为 \(1\)。
所以,可以发现,每一次都操作 \(0\) 的数量等于 \(1\) 的数量的序列一定不劣。
然后每一次都找最长的序列,就为最优的方案了。
然后就可以发现,我们的问题变为了给一个序列,需要不断的找到最长的 \(0\) 的数量等于 \(1\) 的数量的序列。
首先 \(O(n \log n)\) 的线段树是显然可以做的。
但由于这道题的最长的 \(0\) 的数量等于 \(1\) 的数量的序列需要满足必须包含整段中的第一个 \(1\)。
我们就有可以想到一个比较套路的方法。
可以发现,我们的最后一次的操作一定是包含所有的 \(1\) 的一个序列。
所以,我们可以假设 \(1,0\) 的个数差是 \(d\)。
那么问题又可以转化为将一个序列使得前面大于等于 \(d\) 个数为 \(0\)。
考虑到我们每次的操作的右端点是单调递增的。
所以每一次我们的操作都是不会影响到前缀值。
可以预处理出前面 \(0\) 的个数比 \(1\) 的个数多的值的最后一个位置。
这样就可以不断的利用前缀转移,时间复杂度 \(O(n)\)。
Code
代码就不放了,还是比较好实现的。