反悔贪心杂题
反悔贪心杂题
笔者水平有限,若有笔误望指出。
笔者认为,反悔贪心其实质仅仅只是一类贪心策略,所谓反悔,仅为一个思维过程,体现为:拿出一个错误的贪心策略(很多时候体现为略去某些限制)并尝试使用更多的策略去修正它
反悔贪心有一个很常见的应用场景:从
同时如果可以设计dp,这个 dp 过程往往也具备凸性(Slope trick?)
关于Slope Trick,斜率优化,反悔贪心,费用流(关于流量的最小费用函数是凸的),闵可夫斯基和, WQS 二分 是互相联系的。
反悔贪心可以从模拟费用流的角度解释:将原题建立费用流模型。
下面的叙述中会偏重“修正”思想。
BZOJ1577
一个贪心策略是能上车就上车,这样显然是错的,所以我们走到一个地方后,需要考虑当车塞满之后,撤销哪些牛让本站牛上车更优秀
可以发现,对于车上的牛而言,保留目的地更近的牛必然更优,所以踢掉原本车上的牛(目的地
数据备份
极为经典
给定
个数,现要求选出 个数字,其不相邻,且权值和最小。
显然会存在一个
我们考虑当前已经选出了
-
选出当前可选的最小数字,并将其两侧标记为不可选
-
撤销掉某次选择,并选上其相邻的两个元素
如果只选择其中一个,那么不撤掉一定更优(对另外的点限制更弱且自身更小)
所以考虑维护这个撤销步骤,朴素的想法是维护两个堆,一个已经操作的堆,一个尚未操作的堆,取最优决策出来贪心。
但是这样是有问题的,因为撤销状态内部是有联系的,譬如你选了
但是注意到这个连锁反应是成段的,也就是设我当前选了
所以不妨将这样的整段限制缩为一个点,这个点的权值就设为两个方案之间的差值。
并且幸运的是,这个权值是容易计算的。
详细的说,最初,我们
定义一个段的权值是变换操作后的代价与原本代价差,则
正确性是显然的,每次我们选择一个段进行操作,都用了最少的代价,且使得选择个数恰好增加一。
所以得到了一个可以使用链表维护段关系的简洁做法。
事实上,这样的反悔贪心,往往在堆中的某个点其已经不代表点了,而是一整段的决策
CF436E
我们仍然考虑从
- 将一个零星变为一星
- 将一个一星改为二星
- 将一个二星改为一星,同时让一个零星成为二星
- 将一个一星改为零星,同时让一个零星成为二星。
改动量显然不会超过两个点,因为改动更多点都可以被以上四个决策平替掉。
让我们看看这需要如何维护:
- 维护零星里最小的
- 维护一星里最小的
- 稍显复杂,代价是
,也即维护零星的最小的 ,二星的最小的 - 类上,代价是
,维护一星的最小 ,零星的最小的
也即我们需要 5 个优先队列维护决策,取最优的扩展即可。
CF280D
这是重要模型,是一个绝妙的想法。
考虑全局问题,我们每次取出最大子段和,然后将这一段取反(乘上
其实是一个反悔机制,新增一段是什么样的:
- 选出一段不交的区间
- 删去原本至多一个区间的一个子区间,并将分裂的两个区间选出一个进行拓展。
而在这个操作里,根据最优性,如果这一次连续删除了两个之前选出的区间,那么上一次选这个必然更优,不可能发生,所以只会删一个。所以我们这样做是对的(只会增加最多一段区间)
所以只需要维护最大子段和以及取到最大子段和的区间,支持乘上
一个绝妙的实现:我们显然需要维护
,分别表示以 为起点的最大子段和,其右端点是 , 同理, 维护取到最大子段和的区间。可以照常更新。 但是我们可以维护两个这样的量(使用结构体),提前将乘上
的部分预计算,那么每次取反相当于交换这两个量,可以避免维护最小值这种东西
在本题可以这样写,然后暴力执行
NOIP模拟赛5.绳网委托
题目没了,我凭记忆描述一下:
给定
考虑最长不降子序列:
可以赋权,将
这也很经典
考虑这类翻转操作,翻转
答案是,原本的某个前缀,加上
那么与上一题的区别是,我们
CF335F
335e已经够恶心了
题意其实是给定序列
- 将
连边,存在完备匹配 最小
假定没有重复元素,可以想到将饼子按照
可以
如果有重复元素怎么办呢?
那就不妨设
那么有:
仍然可以
好了现在我们给出了一个
- Slope Trick
- 贪心
好像有凸性,只看
回到最开始的条件,我们假设不存在完备匹配,应当可以调整
例如如果有
考虑我们将一类饼干新加入决策集合(权值递减),决策其实并不多:
- 直接给钱
- 让还没指定白嫖对象的来白嫖
- 撤掉之前某个白嫖的,连着白嫖两个
里面最优秀的显然还是能够白嫖就白嫖。
我们考虑维护一个小根堆,里面维护 当前所有白嫖决策的花费,那么当前还能够白嫖的元素是可以计算的:总个数减去两倍的白嫖次数。
当考虑新加入
然后考虑剩下的不能够白嫖的。
设
-
(这是可能发生的,会有复杂的白嫖方案)将其替换为白嫖
是不劣的,买了它后还能多嫖一个,所以还有新的白嫖方案是舍弃 ,嫖两个也就是两个白嫖方案。
-
此时考虑
,这是买 白嫖两个 的收益,我们当前面临选择哪个决策更好,我们可以当作白嫖了物品 ,因为它对于后续的影响等价于一个物品(如果 的话) 和物品 因为它后续影响是一样的(你可以看作两个方案之间转化的代价)所以有方案
和 两个。
我们删去原本的方案,加入这两个新的白嫖方案即可。
Raper
这题有难度啊。
那么考虑 WQS 二分,问题就变成了每次配对有一定代价,求最小代价。
考虑当前的光盘可以分为几类:
- 没有操作的
- 半成品
- 成品
而我们显然能够变成半成品都变,这不会劣,那么每一时刻只会多一个初始权值
有如下决策:
- 将半成品变成成品:
- 将一个成品的后半工序变成
: - 啥也不干
用两个堆,第一个堆维护成品的
每次从三类决策里找到一个更新即可。
校内模拟赛题:楼房搭建
给定序列
,你最初有一个全零的序列 ,每次可以进行两次操作之一:
- 选择
, - 选择
, 求使得
的最小操作次数。
一个很蠢的想法是每次不足就放
但可能会在后面造成极大的浪费(中间极高,两侧较小),那么在这个较高的位置时,我们将之前的
但是这样又会导致给到第三楼
发现第三楼可以在不改变第二楼高度的前提下自己拔高
也就是说,在当前楼尽量贪,而如果在后面发现不合适(矮了),也可以在不改变上一层和上上一层的条件下只改动这一层(按
可以存下当前可以执行的
如果当前操作下后一栋楼的基础高度就已经满足要求了,就可以开始新的一段了(
Jewels
考虑
- 给已经拿过的再拿一个
- 新开一个
,删掉一个之前的 - 连拿三个新的,删掉之前一个
考虑到每一类必然是递减拿,且最少拿两个,所以给最大值和次大值取平均是不影响答案的。
使用三个优先队列
维护所有的物品 维护所有的未拿的连续三个 维护已经拿了的可以删的元素
每次有:
- 若
堆顶的元素从未取出过,说明这个无法参与,那么有如下决策: - 连拿三个新的,删掉之前的一个
- 拿一个已经拿过的
- 扔掉之前的一个
,连拿两个堆顶元素(至少两个) - 此刻,注意到每类元素最大值和次大值相同,那么当前堆里面已经取出的元素(包含它自己)每一类至少有两个,全拿了一定最优
所以所谓的 “删掉之前的一个
笔者粗浅的认为:
- 反悔贪心本质其实是在普通贪心的设计上多考虑一个名为撤销的设计步骤,曰之反悔。
- 其往往答案具备凸性,可以考虑其他操作:WQS等
- 暴力启发思路
- 考虑局面的变化情况
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!