CF1398F Controversial Rounds 题解
Post time: 2021-10-29 18:22:46
贡献一个官方题解做法的详细解释。
首先注意到一个贪心的思路,从前往后如果能够使某一段长度 \(=x\) 就一定会使其 \(= x\) 或 \(\geq x\)。
考虑设一个函数 \(f(pos,x)=npos\) 表示当限制长度为 \(x\) 时,从 \(pos\) 这个位置开始往后,第一个能够出现连续 \(x\) 个 0
或 1
的位置为 \(npos-1\)。如果能够 \(O(1)\) 求出这个函数的值,那么每一次都令 \(pos=npos\) 继续往下做,由于每一次至少会加 \(x\),所以这样的复杂度就是 \(O(n\ln n)\)。
如何求这个函数的值呢?再考虑设两个数组 \(nxt0_i,nxt1_i\) 分别表示从 \(i\) 开始的最长 0
段和 1
段的长度。这个可以倒序递推求得。再设 \(p0_x\) 存下所有的下标 \(i\) 满足 \(i\) 开始往后有连续的 \(x\) 个 0
,且 \(i=1\)(开头)或者 \(s_{i-1}=1\),\(p1_x\) 同理。
考虑对于某个 \(x\),从 \(1\) 开始走,设当前走到 \(now\),如果 \(nxt0_{now}\geq x\),则 \(npos=now+x\);否则就找到 \(p0_x\) 中 \(\geq now\) 的最小的位置(使用双指针实现),设其为 \(tmp\),则 \(npos=tmp+x\)。对 \(nxt1\) 和 \(p1\) 的处理同理,这样就能做到最开始的 \(O(1)\) 求得 \(f(pos,x)\),所以总复杂度是 \(O(n\ln n)\)。
本人代码过于冗长,就不贴 code 了,CF官方题解上的代码写的比我要好。