Problem
给一个序列,一次操作可以使得任意元素+1/-1,问最少多少次操作可以使得整个序列递增或递减?
Solution
能否只构造成递增来解决?
当然可以,如果想要构造成递减,只需要把序列逆序,然后构造成递增。
假设我们只有 2 个数字 [10, 6],那么我们可以将 6 向上移动 4 步或 10 向下移动 4 步;无论哪种方式,成本都是 4。同时,以同样的成本,我们还可以制作 [7, 7] 或 [8, 8] 或 [9, 9] 或 [10, 10]。
假设我们支付了 4 的成本并使其成为 [10, 6] → [6, 6],并且由于我们已经支付了成本,以后如果我们改变主意,我们可以自由地向上移动 [6, 6]到 [7, 7], [8, 8], …, 无需额外费用,因为 [7, 7], [8, 8],[9, 9]… 都需要我们已经支付的 4 个步骤. 数字 [6, 6] 现在向上自由。
一个向上的自由数字可以自由上升直到它之前的最大数字,并作为它的最低值存储。对于每个数字,我们找到它的向上空闲数并制作向上空闲数组。保证我们总是可以使用这个更新的空闲数组来增加数组。
例如,如果向上自由数组是 [1, 7, 6, 3],我们可以创建一个零成本的递增数组 [1, 7, 7, 7],因为最后 6, 3 是向上自由的。
如果下一个数是5,那么我们以2为代价减少7→5,新的向上自由数组变为[1,7,6,3]→[1,5,6,3,5],而这个数组可以成为零成本的递增序列 [1, 5, 6, 6, 6]。
总之,如果新数字大于迄今为止最大的向上自由数字,则追加它,因为序列已经在增加。但如果不是,则以差值为代价,将最大的向上自由数减少到与新数相同;这两个数字现在都向上免费了。第二大数字现在成为新的高度。
我们使用最大堆来存储这些向上的空闲数,以在 O(log(n)) 时间内找到最大的一个。
Code
1 | # |
本文作者:jujimeizuo
本文地址: https://blog.jujimeizuo.cn/2023/01/14/codestudio-weekend-contest-56-ninja-and-the-challenge/
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0 协议。转载请注明出处!