[CP / Codeforces] “使用最小操作次数构造不下降序列类”题目

C. Squaring - 1800*
E. Look Back - 1700*


这两道题本质上是相同的(前者来自最近的 Div.2,后者来自两个月前的 Div. 3)。

E. Look Back [solution]

贪心策略可以很容易地想到——计算出每个元素的最小操作次数,累加可得最终答案。难点在于,我们不能直接将 “操作” 应用于元素上,否则可能会出现溢出,轻则 WA,重则 RE。

于是我们就会想,是否能在仅维护操作次数、不改变输入数组的值的前提下计算出最终答案呢?

这是完全可以的!不过,需要一点小小的数学推导:

记原数组为 \(a\),操作次数数组为 \(op\)\(op[i]\) 表示原数组的第 \(i\) 个元素 \(a[i]\) 所需的最小操作次数,根据上面的分析得 \(ans=\sum\limits_{i=1}^{n}op[i]\)

假设我们现在已经通过某种方式计算出了 \(op[i]\) , 其中 \(1\leq{}i\leq{}k<n\),现在想要计算 \(op[k+1]\)

根据题目要求,此时 \(a[k]\)\(op[k]\) 次操作下的值变为了 \(2^{op[k]}\cdot{}a[k]\),注意我们并没有把这个值真的赋给 \(a[k]\),仅用于推导。那么,\(op[k+1]\) 就等于为了满足

\[2^{op[k]}\cdot{}a[k]\leq{}2^{op[k+1]}\cdot{}a[k+1] \]

所可以取的最小值,注意这里 \(op[k], op[k+1]\) 均大于等于零

分类讨论。

如果 \(a[k]=a[k+1]\),显然 \(op[k+1] = op[k]\);
如果 \(a[k]>a[k+1]\),那么 \(op[k+1] = op[k] + t,\ t\in{}\mathbb{N}^*\)
如果 \(a[k]<a[k+1]\),那么 \(op[k+1] = \max(0, op[k] - t),\ t\in{}\mathbb{N}^*\)

可见,我们只需要找到 \(t\) 就行了。

\(a[k]>a[k+1]\) 为例,此时不等式变为:

\[a[k]\leq{}2^{t}\cdot{}a[k+1] \]

\(op\) 数组完全无关!假设原数组元素的最大值为 \(M\),即便使用最简单的枚举法,找到这样的 \(t\) 也只需要花费 \(O(\log{M})\) 的时间,足够快了。

因此,我们可以使用上述算法计算出 \(op\) 数组,并得到最终答案,时间复杂度 \(O(n\log{}M)\),使用二分查找可以进一步优化到 \(O(n\log\log{}M)\)

C. Squaring [solution]

(这道题的推导和上面大相径庭,请读者自行尝试。)

posted @ 2024-07-28 20:50  ZXPrism  阅读(37)  评论(0)    收藏  举报