反悔贪心

反悔贪心

一般贪心仅能解出局部最优解,显然存在题目不满足局部最优解等价于全局最优解,于是引入反悔贪心。

实现

每次都进行操作,若以后有更优情况,撤销这次操作(反悔),本质为跑一遍局部最优假贪心,再通过反悔操作得到答案。

不难发现反悔贪心的核心在于维护反悔操作所需的值,所以当有些题目可以很方便地维护出操作贡献时,可以考虑反悔贪心。

可以参考一个好用的大根堆:

应用

P2949 [USACO09OPEN] Work Scheduling G

n 项任务,每一时刻可以完成一项任务,第 i 项任务的截止时间为 di ,价值为 pi ,求最大价值。

n105

首先按截止时间排序。若当前任务可以做,就先去做;否则若当前任务价值高于做过的最小价值的任务,则将其替换为该任务。

时间复杂度 O(nlogn)

类似的题目:P4053 [JSOI2007] 建筑抢修

CF865D Buy Low Sell High

已知接下来 n 天的股票价格,每一天可以选择买进、卖出或不做,求 n 天后的最大利润。

n3×105

对于每一个形如“第 i 天买入,第 j 天卖出”的决策,假想出一个价格为 val 的物品,使得“第 i 天买入,第 j 天卖出,同时买入这个价格为 val 的物品,并在第 k 天卖出“等价于"第 i 天买入,第 k 天卖出",就实现了反悔操作。

设第 i 天的价格为 ai ,则 (ajai)+(akval)=akai ,化简得 val=aj

于是维护一个堆代表可选物品价格,从前向后遍历每一天。对于第 i 天,找到堆中最小价格 aj 并加入 ai 代表 ai 这一天可选。若 ai>aj ,则把答案加上 aiaj ,并向集合中再次加入 ai 代表假想得反悔物品,并删除 aj

时间复杂度 O(nlogn)

P3545 [POI2012] HUR-Warehouse Store

现在有 n 天,第 i 天上午会进货 Ai 件商品,中午会有顾客购买 Bi 件商品,可选择满足或无视。求最多能够满足多少顾客的需求。

n2.5×105

每次能选就选,不能选时如果之前选的最大数大于当前数,那显然用当前数替换之前最大数要更优。

时间复杂度 O(nlogn)

P1484 种树

n 个数中选出至多 k 个两两不相邻的数的最大和。

n3×105

设当前选出的最大的点为 id ,它左右两边的点分别是 x,y ,就删掉这三个点并新建一个点权为 ax+ayaid 的,这样下次选出这个点 p 时就实现了反悔操作。因为现在舍弃了 id ,所以之后也不会选 id ,故正确。用链表维护相邻点即可做到 O(nlogn)

类似的题目:

CF436E Cardboard Box

n 个关卡,每个关卡可以花 ai 代价得到一颗星,也可以花 bi 代价得到两颗星,也可以不玩。求获得 w 颗星最少代价。

n3×105

考虑如何从选了 i 颗星的方案扩展得到选 i+1 颗星的方案

  • 选一个没有选星星的位置 i ,付出 ai 的代价选一颗星。
  • 选一个已选一颗星的位置 i ,付出 biai 的代价选两颗星。
  • 选一个已选一颗星的位置 i ,再选一个没有选星星的位置 j ,将原来 i 位置上的星星反悔不选,再在 j 位置上选两颗星,代价为 bjai
  • 选一个已选两颗星的位置 i ,再选一个没有选星星的位置 j ,将原来 i 位置上的星星反悔选一颗星星,再在 j 位置上选两颗星,代价为 bj(biai)

用堆维护即可做到 O(nlogn)

P3045 [USACO12FEB] Cow Coupons G

n 头奶牛,第 i 头初始价格为 pi ,使用优惠券时价格为 ci 。你有 k 张优惠券和 m 元,求购买奶牛的最大数量。

n5×104

能够使买入奶牛数量增加的三种操作:

  • 用优惠券买一头未买的奶牛。
  • 不用优惠券买一头未买的奶牛。
  • 将一头用优惠券买的奶牛替换为不用优惠券买的同一奶牛,并用优惠券买入一头未买的奶牛。

用堆维护即可做到 O(nlogn)

P5470 [NOI2019] 序列

给定 a1n,b1n ,需要分别对两个序列各指定恰好 k 个下标,要求至少有 l 个下标在两个序列中都被指定,最大化这 2k 个下标在序列中对应的元素的总和。

多测,n106

首先考虑没有 L 限制的贪心,从 a,b 中各选 K 个最大的即可。

对于 L 的限制,考虑反悔贪心,每次选取增量尽可能大的操作反悔,使得每次返回后都能使当前同时出现在两个序列中的点数多一。

  • 找一个选了的 ai 和一个选了的 bj ,用 bi 代替 bj ,增量为 bibj
  • 找一个选了的 ai 和一个选了的 bj ,用 aj 代替 ai ,增量为 ajai
  • 找一个选了的 ai,bj ,再找一个没选的位置 k ,选 ak,bk 代替 ai,bj ,增量为 ak+bkaibj
  • 找一个选了的 ai,bj ,再找一个都选的位置 k ,选 aj,bi 代替 ak,bk ,增量是 aj+biakbk

时间按复杂度 O(nlogn)

[AGC018C] Coins

x+y+z 个人,第 i 人有 ai 金币、bi 银币、ci 铜币。要选出 x 个人获得其金币,y 个人获得其银币,z 个人获得其铜币,在选人不重复的情况下求币总数的最大值。

x+y+z105

考虑先随便整出一种合法的方案,然后反悔操作都是类似于环的重分配操作,一共五种:

  • AB,BC,CA
  • AC,CB,BA
  • AB,BA
  • AC,CA
  • BC,CB

开六个堆维护每一步转换的决策即可,时间复杂度 O(nlogn)

类似的题目:CF730I Olympiad in Programming and Sports

CF802O April Fools' Problem

n 道题,第 i 天可以花费 ai 准备一道题、花费 bi 打印一道题。

每天最多准备一道、最多打印一道,准备的题可以留到以后打印。

求准备并打印 k 道题的最小花费。

n5×105

先用 wqs 二分去掉恰好 k 题的限制。考虑在每次打印的时候选取准备花费最少且准备+打印总花费为非正数的题目进行打印,但是这样会使得后面一个打印花费更优的位置无法匹配,于是引入反悔操作。

用一个小根堆维护之前的所有决策,每次取出价格最低的决策,将当前打印的花费加上决策花费后,如果总花费为非正数,则先选择该决策。又由于:

ai+bjbj+bk=ai+bj+(bj+bk)

于是把当前打印的花费的相反数加入堆中即可,时间复杂度 O(nlognlogV)

CF280D k-Maximum Subsequence Sum

给出一个长度为 n 的数列, m 次操作,每次有两种:

  • 修改某个位置的值。
  • 询问区间[l,r] 里选出至多 k 个不相交的子段和的最大值。

n,m105k20

考虑用线段树维护反悔贪心。处理一个区间询问时贪心选最大子段和,再将其全部取相反数,这样下一次算到时就算反悔。

时间复杂度 O(nklogn)

CF2063D Game With Triangles

平面上有 n+m 个点 (a1n,0)(b1m,2) 。每次可以选择三个点组成三角形并删去,分数为其面积。

求最多操作次数为 kmax ,并对于操作 1kmax 次求出最大得分。

n,m2×105

显然有 kmax=min{n,m,n+m3} ,面积即为纵坐标相同点的横坐标差。

考虑反悔贪心,则每次可以选择:

  • 选一个 a 为边的三角形。
  • 选一个 b 为边的三角形。
  • 撤销一个 a 为边的三角形,选两个 b 为边的三角形。
  • 撤销一个 b 为边的三角形,选两个 a 为边的三角形。

不难发现为了最大化面积,固定顶点是 a 还是 b 后贪心选取另一边最左和最右的两个点最优。于是维护堆存储两端线段长度即可做到 O(nlogn)

本文作者:wshcl

本文链接:https://www.cnblogs.com/wshcl/p/18712932/ReversibleGreedy

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   wshcl  阅读(1)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开