CF1845E
首先我们容易发现如果给每个球一个编号,他的相对位置是不变的
于是我们不妨把原问题转化为一个常为\(k\)严格递增的序列\(b_i\)表示这\(k\)的球的位置
我们发现如果递推操作次数显然不记录序列的状态的话是比较难办的。于是我们考虑正难则反,考虑对于一个序列\(c_i\),判断他能不能让\(b_i\)通过操作\(k\)次得到
容易发现如果想得到\(c_i\),要满足以下条件:
- \(|b| = |c|\),表示序列\(b_i\)与\(c_i\)的长度相等
- \(\sum_{i=1}^k{|b_i-c_i|}\leq k\),表示最少操作次数\(\leq k\)
- \((k - \sum_{i=1}^k{|b_i-c_i|})\mod 2 = 0\),表示剩下的操作通过来回移动一个小球来消耗掉
于是我们按照序列顺序dp,设\(dp_{i,j,s}\)表示前\(i\)个位置放\(j\)个小球,此时操作次数为\(s\)的方案数
容易得到递推式:
其中前半部分表示第\(i\)个位置不选小球的贡献,后半部分则表示\(i\)个位置选小球的贡献
这样的复杂度是\(O(n^2k)\),据说加上一个滚动数组后卡常也能过,但从理论上这个复杂度我们是不满意的。我们考虑优化这个dp
方法1:
关于不降序列对应位置距离之和,有经典套路:在每个间隔处统计答案。 我们设\(f_{c,i}\)表示对于序列\(b_i\)和\(c_i\)的前数值\(\leq i\)的部分的\(b_i\)的个数和\(c_i\)的个数差几个(也可以理解成前\(i\)个位置原先小球个数-操作后小球个数),其中差可以为负。
容易发现对于一个已知序列\(c_i\),其变为\(b_i\)最小操作次数为\(\sum_{i=1}^n{|f_{c,i}|}\)
而优化dp的过程通常需要以下两种条件:
- 考虑特殊条件
- 去除多余状态
如果细心可以发现题目有一个隐含条件,即\(|f_{c,i}-f_{c,i-1}| \in \{0,1\}\)
假设存在一个序列\(c_i\)让\(|f_{c,i}|\)足够大,则\(|f_{c,i}|\)可以构造成形如\(1,2,3,...,f_{c,i}\)的等差数列的形式
根据等差数列求和公式,容易得到序列\(c_i\)变为\(b_i\)的最小操作次数为\(O(f_{c,i}^2)\)
但根据题目要求,最小操作次数应该\(\leq O(k)\),所以\(|f_{c,i}| \leq O(\sqrt k)\)
于是我们考虑把\(|f_{c,i}|\)带入dp式子中代替\(j\)项定义
设\(dp_{i,j,s}\)表示前\(i\)个位置中原先球的个数-操作后小球个数\(=j\),最小操作次数\(=s\)的方案数
容易得到递推式:
最终复杂度\(O(nk\sqrt k)\)
方法2:
仔细一想上面的方法,可以发现我们优化后的dp式子相对与原先的dp式子记录的状态数完全没有改变,且我们并没有优化转移,所以说明原先的dp式子加一点小优化复杂度也是不变的
我们同样用一种更感性的方法证明上面的问题
我们考虑如果\([1,x]\)内全是球,我们想把这些球都移走,则我们需要的最小操作次数是\(\sum_{i=1}^x{i}=O(x^2)\),但我们要求最多操作\(\leq O(k)\),则\(x \leq O(\sqrt k)\)
于是我们可以求出dp转移时\(j\)的范围\(\in [pre_i - \sqrt k, pre_i + \sqrt k]\),其中\(pre_i\)表示操作前的前i个位置的球的个数
同样得到最终复杂度\(O(nk\sqrt k)\)