学习笔记—反悔贪心

djy 的《浅谈反悔贪心》,这里做的题都来自反悔贪心题单

\(\texttt{update on 2022.7.29}\):以前写的太乱了,重构了文章。

反悔贪心

反悔贪心类似 DP,每天我们都可以进行一定操作使得当天我们的收益达到最大值,但是这样的操作可能会使得后面几天达不到最优,这就迫使我们放弃前面的决策。

我们将放弃前面的决策称为反悔,做出新的决策称为贪心,我们需要做的就是在所有决策中选择最优的那个。

例题

CF865D Buy Low Sell High

已知接下来 \(n\) 天的股票价格,每天你可以买进一股股票,卖出一股股票,或者什么也不做。\(n\) 天之后你拥有的股票应为 \(0\),当然,希望这 \(n\) 天内能够赚足够多的钱。

考虑一次股票交易的过程,一天内买入一次再卖出一次等同于什么也没发生,于是我们考虑一个贪心,每次让之前最小的那个和当前这个配对。

但是这样是错误的,可能将一个较小的日子留给后面的更优,所以我们需要反悔的操作,让后面的将这一天的决策抵消掉。

设第 \(i\) 天的交易价格为 \(c_i\),则在 \(i,k\) 之间的 一次交易收益就是 \(c_k-c_i\)

如果我们已经在 \(j\) 时将 \(i\)\(j\) 匹配了,我们已经得到了 \(c_j-c_i\) 的贡献,现在我们需要将另外的贡献补上:\(c_k-c_i=(c_k-c_j)+(c_j-c_i)\)

这样我们只用在这一天交易结束后将这天的卖出价格加入堆中即可。

P2107 小Z的AK计划 & P4053 [JSOI2007]建筑抢修

在一条数轴上有 \(n\) 个点,初始在 \(0\) 位置。每向正方向走一步都消耗 \(1\) 单位的时间,每到达一个点可以花费 \(t_i\) 的时间 获得 \(1\) 的收益,也可以直接路过。

\(m\) 的时间内,最大收益是多少?

\(n\le 10^5,0\le m,x_i\le 10^{18},0\le t_i\le 10^9\)

从前往后枚举我们走到哪里,将新的点加入决策。

什么时候需要反悔?当已经消耗了 \(>m\) 的时间。选择消耗时间最大的删去即可。

P3620 [APIO/CTSC 2007] 数据备份

一个环(链)上有 \(n\) 个元素,要求选取的任意两个元素互不相邻,求选出 \(k,k\in\left[1,\dfrac{n+1}{2}\right]\) 个元素分别可以获得的最大价值是多少。

每次都要新选择一个点,我们有两种操作:

  • 加入一个独立的点。
  • 将与一些点相邻的点同时取反。

只用一个链表,加入一个点后将 \(p+s-v\) 替换为这个点的权值即可,用堆每次选择最大值即可。

CF730I Olympiad in Programming and Sports

\(n(n\le 10^5)\) 个人,第 \(i\) 个人有属性 \(a_i,b_i\),要求选出 \(A\) 集合至多 \(p\) 人,\(B\) 集合至多 \(s\) 人,使得选出的人相应属性值之和最大。

先选出 \(a_i\) 最大的 \(p\) 个加入 \(A\) 集合,之后一个一个加上 \(B\) 集合,我们每次有以下两种操作:

  • 直接加入一个 \(B\)
  • 将一个人由 \(A\) 转为 \(B\),再选择一个 \(A\)

用三个堆对上面信息分别维护即可!

\(\texttt{update}\):网络流做法:

  • 源点 \(s\) 到每个点建一条流量为 \(1\),费用为 \(0\) 的边(每个人只能只能参加一种比赛)。
  • 建三个汇点,汇点 \(t1\) 控制参加编程的,汇点 \(t2\) 控制参加体育的,汇点 \(t\) 控制参加 \(t1\)\(t2\) 的总人数。
  • 每个人两种实力分别向 \(t1\)\(t2\) 建流量为 \(1\),费用为负实力。

然后就跑最小费用最大流啦!

AT2672 [AGC018C] Coins

\(n(n\le 10^5)\) 个人,第 \(i\) 个人有属性 \(a_i,b_i,c_i\),要求选出 \(A,B,C\) 集合分别 \(p,q,s\) 个人,保证 \(p+q+s=n\),使得选出的人相应属性值之和最大。

一种比较显然的想法是将将 \(B_i\) 赋为 \(B_i-A_i\)\(C_i\) 赋为 \(C_i-A_i\),就转化为了上一个问题。

\(\texttt{update}\):有一种可以推广到 \(4,5,\dots\) 中限制的做法:

发现每次操作我们只有以下几种方案:

  • \(x\rightarrow y,y\rightarrow z,z\rightarrow x\)
  • \(z\rightarrow y,y\rightarrow x,x\rightarrow z\)
  • \(x\rightarrow y,y\rightarrow x\)
  • \(x\rightarrow z,z\rightarrow x\)
  • \(y\rightarrow z,z\rightarrow y\)

用六个堆维护即可。

CF802O April Fools' Problem medium & hard

每天可以花费 \(a_i\) 准备一题,花费 \(b_i\) 打印一题,每天最多准备一题打印一题,求打印 \(k\) 题的最小花费。

如果没有 \(k\) 的限制,那可以将准备看作买入一只股票,打印看作反向卖出一只股票,转化为第一题的套路。

考虑如何限制 \(k\) 只股票。如果我们将每次买卖的收益同时增加一个 \(d\),买卖的优劣性相对不变,但我们会在原来的基础上多进行一些交易。那么我们二分这个 \(d\) 直到正好购买 \(k\) 次股票即可。

CF436E Cardboard Box

\(n\) 个关卡,对每个关卡,你可以花 \(a_i\) 代价得到一颗星,也可以花 \(b_i\) 代价得到两颗星,也可以不玩。问获得 \(w\) 颗星最少需要多少时间。

我们进行 \(w\) 次操作,使我们多选择一棵星星,有以下几种方法:

  • 直接选择一颗星星;
  • 将一颗星星变为两颗;
  • 将一颗星星由一颗反悔为不选择,再选择两颗;
  • 将两颗星星反悔为一颗,再选择两颗。

那么我们需要维护 \(a_i(\min\&\max),b_i(\min),b_i-a_i(\min\&\max)\) 五个堆。

P5470 [NOI2019] 序列

给定长度为 \(n\) 的数组 \(\{a\},\{b\}\),要求在他们中分别取恰好 \(k\) 个值,且相同下标且 \(a,b\) 中都选取的对数 \(\ge l\),求最大选择价值之和。

\(n\le 2\times 10^5\)

先在两个数组中选择最大的 \(k\) 个,如果相同位置的不到 \(l\),考虑依次增加。想要增加一个相同位置,有以下四种方案:

  • 将一个单独选择的 \(a\) 变成一个已经选择 \(b\) 但没有选择 \(a\) 的;
  • 将一个单独选择的 \(b\) 变成一个已经选择 \(a\) 但没有选择 \(b\) 的;
  • 将一个单独选择的 \(a\) 和一个单独选择的 \(b\) 都删去,变成一个没有选择的 \(ab\) 对;
  • 将一个已经选择的 \(ab\) 拆掉,和一个单独选择的 \(a\)、单独选择的 \(b\) 分别合并变成两个 \(ab\) 对。

\(6\) 个堆分别维护上面的选择情况,取最大值转移即可。

(乱入)贪心杂题

P2512 [HAOI2008]糖果传递

\(n\) 个小朋友坐成一圈,每人有 \(a_i\) 个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为 \(1\)。问最后所有人糖果数量均衡后的最小代价。

\(n\le 10^6\)

如果题目只是在链上,就变成了均分纸牌的问题,假设每个人现有纸牌数为 \(a_i\),平均为 \(ave\)\(a_i-ave\) 前缀和为 \(pre_i\),则答案为 \(\sum{|pre_i|}\)

回到这道题上,发现最优解一定存在环上两个人之间不存在糖果传递,可以想到断环成链。

如果断掉环上第 \(k\) 条边,则贡献依次为 \(|pre_1-pre_k|,|pre_2-pre_k|\dots\)

这就是“仓库选址”问题啦!直接将 \(k\) 定位所有 \(pre\) 的中位数,求出答案即可。

P8272 [USACO22OPEN] Apple Catching G

假设在 \(a(a_x,a_t)\) 点有奶牛,在 \(b(b_x,b_t)\) 有苹果 \((a_t\le b_t)\)\(a\) 可以借助 \(b\) 的充要条件为:

\[a_x-(b_t-a_t)\le b_x\le a_x+(b_t-a_t)\\ \Downarrow\\ \begin{cases} a_x+a_t\le b_x+b_t\\ a_x-a_t\ge b_x-b_t \end{cases} \]

第二个式子直接 \(x-t\) 从小到大的顺序搞定(注意如果值相同 \(t\) 大的优先),这样只要每个数匹配在它之前的点就都是合法的,接下来只用满足第一个式子。

考虑两头奶牛 \(a_1,a_2(a_x-a_t<b_x-b_t)\) 一起匹配苹果,我们会让 \(a_1\) 优先匹配苹果中 \(b_x+b_t\) 最小的,把剩下的留给 \(a_2\)

为什么这样是对的呢?

显然 \(b_x+b_t\) 越小越难被匹配,那么如果可以被匹配,直接匹配一定最优。

而且如果 \(a_1\)\(a_2\) 都能够匹配同一个 \(b\),让他们任何一个去匹配是相同的。

那么就这样被简单地证明了。

实际操作中可以用 multiset 来支持查询比 \(a_x+a_t\) 大的数即可。

P2672 [NOIP2015 普及组] 推销员

发现答案只可能是一下两种情况:

  • 选择最大的 \(x\) 个推销疲劳值。

  • 选择最大的 \(x-1\) 个推销疲劳值,并选择一个距离较远的。

至于为什么只选择 \(x-1\) 个而不是 \(x-2\) 或更少:

加入我们要将第 \(x-1\) 大的换为更远的,完全可以用第 \(x\) 大的而不是 \(x-1\) ,显然这样减小的更少呀。

商店zr

有一个商店,每个天会进货固定 \(m\) 中物品分别 \(b_i\) 个,每个单价为 \(a_i\),若 \(b_i=-1\) 表示有无限个。

在接下来的 \(n\) 天内,每天顾客会来购买最便宜的 \(c_i\) 个物品,问最终商店收益为多少。

\(n,m\le 2\times 10^5,1\le a_i,c_i\le 10^6,-1\le b_i\le 10^6\),保证存在至少一个 \(b_i=-1\)

考虑这本质是一个贪心过程,每个月丢给你一堆物品,一定先选择小的并有库存的,没了再选择大的。

这样我们的讨论就不能够脱离贪心的特点,固定了向优化贪心的方向走。

\(\bigstar\texttt{Trick}\)单位价值下降的天一定放在一起考虑!!!最后剩下单位价值单调不增的一些连通块,将他们合在一起考虑。

posted @ 2021-11-17 18:27  EricQian06  阅读(109)  评论(1编辑  收藏  举报