Solution CF2061 C~E
Solution CF2061C Kevin and Puzzle
大炮打蚊子做法。
首先能写出一个简单的平方 dp:记 \(f_{i,j,0/1}\) 表示前 \(i\) 个人有 \(j\) 个说真话,第 \(i\) 个是否说真话的方案数。则有:
发现形式为交换两个数组,然后将其中一个全部赋值为 \(0\) 再对其中某一个单独操作。
交换数组可以通过滚动代替掉,赋值为 \(0\) 直接使用线段树维护数组并且打标记即可。
时间复杂度 \(O(n\log n)\)。
Solution CF2061D Kevin and Numbers
妙妙题。
第一眼看这个似乎不太好做,因为每次选择合并哪两个会对后面产生影响。
但是我们发现 \(|x-y|=1\) 有一个特殊的性质,就是确定了合并后的 \(x+y\) 就能倒退出唯一的 \(x,y\)。
利用这个性质,考虑倒着变成每次选择 \(b\) 中一个数分裂成两个。
大力 STL 维护,每次找 \(b\) 中最大的数,如果其出现数量比 \(a\) 中的出现数量小无解,因为已经是最大的数了。遇到多余的 \(1\) 无法分解和匹配时也是无解。
时间复杂度 \(O(n\log n)\)。
Solution CF2061E Kevin and And
也是妙妙题,但是因为【】调了好久。
考虑 \(m\) 很小能带来什么:由于多个操作作用到一个值上并不好处理,考虑枚举所有 \(2^m\) 种可能的操作,算出 \(w_{i,j}\) 代表对于 \(a_i\) 进行 \(j\) 次操作能从和上减去多少。这个需要稍微精细实现一下做到 \(O(n2^m)\) 而不是 \(O(nm2^m)\)。
直接做还是不太好处理,考虑对 \(w_i\) 差分一下,变成了多进行一次操作产生的额外贡献。
发现差分出来的 \(w_i\) 一定单调不增,因为新操作一次能产生的贡献越来越小。直接对差分出来的所有数排序取前 \(k\) 大,则选中了 \(i\) 的 \(j\) 操作,所有小于 \(j\) 的操作已经被选择过了。
时间复杂度 \(O(n2^m+nm\log(nm))\)。