一类堆贪心前 k 优方案题

一类堆贪心前 k 优方案题

给雷暴磕头了/kt 给雷暴磕头了/kt 给雷暴磕头了/kt

求组合前 k 大用堆贪心,需要构造转移使得状态之间成为一个外向树,并且转移不重不漏,而且一个状态的后继很少。这样用堆贪心贪出来即可。

P1

给定非负整数构成的多重集,求前 k 小子集和。

从小往大排序,想用“先移动最右边的到指定位置,再移动最左边的到指定位置......”这个策略去描述状态的转移。首先选把选了前 i 个的状态 push 到堆里面。发现描述转移的时候需要记录的信息有:前缀 [1,x] 还没有移动,当前正在移动的物品位于 y,上个物品停在了 z.转移就是 y 继续往后一格但是不能越过 z,或者 y 彻底停住再去移动 x

P2

n 个正整数数组,一个方案的代价是每个数组里面恰好选一个数再求和,求前 k 小的方案的代价。P2541

设计策略是挨个数组确定选第几个。也就是 (pos,x) 表示选到了第 pos 个数组,当前这个数组选的是第 x 个人.但是发现计重了,(2,1,1)(2,1)(3,1) 两个都算到了。原因在于 x 可以为 1,但是后缀还没决策的数组选的全是 1,于是对于一个状态来说无法唯一确定它的 pos

于是强制让 x2,那么转移就分三种:

  • 当前数组从第 x 个换成第 x+1 个;
  • 换到下一个数组,从第 2 个开始选;
  • 如果当前 x=2,说明可以撤销回 x=1,然后从下一个数组的第 2 个开始选。

为了让第三个转移非负,按照 a2a1 将所有 a 排序即可。

除了全选第一个的最优解以外,其余的均能转移到并且仅被转移一次(按照这个策略去尝试把一个状态凑出来,只有一种方案)。

P3

P2 改成每个数组要选数量在 [Li,Ri] 中的若干个数。P6646

对于单个数组,用 P1 中的方法已经可以求出前 k 小的方案,看成一个黑箱,结合 P2 做法即可。

P4

给定非负整数 a,对于排列 p 代价为 aipi,求前 k 小的代价和。

最优就是 a 降序排序之后 pi=i,然后考虑一个排列从后往前插排去得到。这个时候状态记录 (p,x) 为现在从后往前插排在将 p 往后移动移到了第 x 个位置。同 P2 中的问题一样,当 p=x 的时候会出现问题,但是套用 P2 中的做法,先强制 x>p,然后再考虑撤销往前也不行,因为这里并不像 P2 中一样可以交换数组之间顺序使得转移非负。

这里转移非负的问题就在于,为了剪枝掉后继个数,当前的 p 已经插排完毕,选择下一个进行插排的 p 的时候想直接通过对 p=x 的状态进行撤销再选择另一个 p(形象一点的描述就是,运用了儿子兄弟表示法)。思路往回推,记录当前已经插排完毕的是哪个 p,选择下一个 p 的时候从最优开始,最优完了再找次优,次优完了再往后找...

于是记录 pre 表示已经考虑完了 >pre 的所有位置,[1,pre] 还没有尝试插排。现在有 pre=p1.如果继续移动 p 那么直接正常做;如果当前的 p 移动完了,去找下一个 p,对 [1,pre] 里面每个 i 记录 fi 表示下一个交换 i 多出来的代价是多少,那么找 f 最小的那个位置当作下一个 p,此时让 pre 不变

那么当 prep 的时候就意味着当前状态的 p 是尝试新开一个 p 得到的状态,那么它的转移就多了一个撤销当前的 p,尝试比它次优的那个 p,于是需要找到按 f 排序之后它的后继。只有 fpre 不是 apre+1apre,其余的 fi 均为 ai+1ai,所以尝试新的 p 的时候单独把 pre 作为一个转移拎出来,现在 fi=ai+1ai,所以直接在主席树上二分即可找到后继。

整理一下现在的转移:

pre=p1 时:

  1. 继续移动 p,此时 xx+1pre 被强制更新为 p1
  2. 选择下一个 p,并且选择的就是 p1,此时 pre 被强制更新为 p2;
  3. 选择下一个 p,选择的是 [1,pre) 中的,此时 p 应选择 f 最小的,pre 不变。

prep 时:

  1. 同上;
  2. 同上;
  3. 类似,选择下一个 p,选择的是 [1,p1) 中的,此时 p 应选择 f 最小的,然后 pre 被更新为 p1
  4. 撤销当前选的 pp 选为 [1,pre] 里面选当前的 f 的后继,pre 不变。

还需要维护各个转移需要的代价,由于只有交换操作,所以用个可持久化线段树就行了。

posted @   do_while_true  阅读(119)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?

This blog has running: 1845 days 1 hours 33 minutes 23 seconds

点击右上角即可分享
微信分享提示