刷题系列——贪心

New Year Snowmen

Description

要堆起一个雪人,需要三个不同大小的雪球。现在有 n n 个给定大小的雪球,问最多能堆起多少个雪人,并输出方案。

Solution

每次用数量最多的三个雪球是最优的。可以用一个单调队列,每次取出最大的三个数,再把余下的丢回队列。


Discounts

Description

超市打折,如果购物车里有至少一个凳子,则可半价购买购物车里最便宜的一个物品。现在你要购买 n n 个物品,其中一些是凳子。你有 k k 个购物车,求一个最优的购买方案,使得花费的价格最少。

Solution

每个购物车的凳子只能优惠价格低于它的,那么优惠它自己是最优的。所以将价格最大的 k 1 k-1 个凳子放入前 k 1 k - 1 个购物车,余下的购物车放全部的其他物品。


叠罗汉

Description

n n 个罗汉,每个罗汉有重量 w w 和力量 s s 。定义一个罗汉的危险值为他上面所有罗汉的重量之和减去他的力量。安排一个顺序使得危险值最大的罗汉的危险值最小。

Solution

如果已经有一个排列,可以对这个排列相邻两个罗汉 i i j j 进行调整, i i j j 交换不会影响他们上下的人,所以考虑 i i j j 哪个在上面最优,因为要让最大值最小,分类讨论两人的危险值或感性猜测,可发现让两个罗汉中 w + s w+s 更小的在上面。最后调整的结果就是将所有罗汉按 w + s w + s 从小到大排序。


建筑抢修

Description

基地里有 n n 个建筑设施受到了严重的损伤,但只有 一个修理工人。修复一个建筑都需要 t i t_i 的时间,工人一次只能修一个。如果某个建筑在 d i d_i 时间之内没有修理完毕 ,这个建筑就报废了。你的任务是制订一个合理的维修顺序,以抢修尽可能多的建筑。

Solution

若第 i i 号出现时间不足,那么前 i i 个建筑中最多修复 i 1 i-1 个建筑。必然选择 t i t_i 较小的前 i 1 i-1 个建筑,给后面的修复留下更多的时间。按 d d 从小到大排序,中途用堆维护 t m a x t_{max} 。如果能修第 i i 个建筑,那么就修,不然从堆中取出所需时间 t t 最大的,如果 t m a x > t i t_{max} > t_i 就不修 m a x max 而修 i i

反悔性贪心

先能选就选,用堆维护代价最大的,如果不能选看看它能不能替换堆中代价最大的。


密码锁

Description

给定 a [ 1 n ] , a i [ 0 , m 1 ] a[1 \sim n], a_i \in [0,m-1] ,每次操作可以在模 m m 意义下对任意一个区间 [ l , r ] [l,r] 整体 + 1 +1 1 -1 ,求最少几次操作可以使所有数字变成0。

Solution

n n 个数前后补上 0 0 ,进行在模意义下的差分,有差分数组 b b ,在模意义下的区间加减转为选择一位 + 1 +1 ,另一位 1 -1 。要让 b b 全为 0 0 m m ,先对 b b 从小到大排序。枚举找到一个分界点 m i d mid ,让 m i d mid 左边的数尽可能接近 0 0 m i d mid 右边的数尽可能接近 m m ,用 m i d mid 左边的数 + 1 +1 ,右边的数 1 -1 互相抵消。如果有多余的,可以贪心地控制多余的数尽可能的接近前缀 0 0 或后缀 0 0 ,就可以自己消自己了。
a n s = m a x { i = 1 m i d b i , i = m i d + 1 n m b i } ans = max\{ \sum_{i = 1} ^ {mid} b_i, \sum_{i = mid + 1} ^ {n} m - b_i\}

这个式子可以用前缀和预处理搞定。


删数问题

Description

给定一个大正整数 S S 你需要去掉其中任意 n n 位数字。剩下的数字按原次序组成一个新的正整数 S S’ 。对给定的 n n S S ,寻找一种方案使得剩下的数字组成的新数 S S’ 最小。

Solution

要让高位尽可能小。先在数字最后一位补一个 1 -1 ,输出时忽略掉 1 -1 。然后从高位向低位枚举,如果在某一个位置数字是递减的,那么将这个位置删掉。如 S = 178543 , n = 4 S = 178543,n = 4 ,删除如下

178543 { 8 } 178543 \quad \{ 8 \} \to 17543 { 7 } 17543\quad\{ 7 \} \to 1543 { 5 } 1543\quad\{ 5 \} \to 143 { 4 } 143\quad\{ 4 \} \to 13 13

如果不够删 n n 个回头重来。


取数游戏

Description

给出 n n 个正整数,你需要把它们连接成一排,组成一个最大的多位整数。

Solution

重载 < < 的定义,如果 a a b b 拼接比 b b a a 拼接大,就认为 a > b a > b 。按照重载的小于号从小到大排序即可。如 12 12 121 121 ,虽然数学中 121 > 12 121 > 12 ,但是因为 12121 > 12112 12121 > 12112 ,所以 12 > 121 12 > 121


Main Sequence

Description

定义幸运数列:空序列是幸运序列。如果 S S 为幸运数列,有一个正整数 k k ,那么 { k , S , k } \{k, S, -k\} 也是幸运序列。如果 S S T T 都是幸运序列,那么 { S + T } \{S+T\} 也是幸运序列。现在给你一个有 n n 个元素的序列每个数的绝对值,同时有 m m 个限制,每个限制为数列的第 i i 个数一定为负数。请你求出这个幸运数列。

Solution

这道题就是一个括号匹配 k k 可以看作是左括号, k -k 可以看作是右括号。因为 m m 个右括号已经确定了,所以我们从后往前扫这个序列。相似的,我们用栈来维护右括号,对于每个数有两种情况,如果他是 m m 个数之一或者不能与栈顶的右括号匹配,那么让他加入未匹配的右括号栈中,否则我们将栈顶的数退栈,表示匹配成功。如果将序列扫完栈不为空,则匹配失败。


兔子和樱花

Description

给定一颗 n n 的点的有根树,每个点 x x 上面有一些樱花 a x a_x ,设 f a x fa_x x x 父亲, s o n f a x son_{fa_x} 为父亲的儿子数。现在可以删掉一些节点,被删除的节点 x x 的樱花会累加到 f a x fa_x 上, x x 的子节点也会接到 f a x fa_x 上。要求删除完 x x 后, a f a x + s o n f a x < m a_{fa_x} + son_{fa_x} < m 。问最多能删多少个点。

Solution

从下向上进行树形 dp,对于每个点,删除的代价为 c i + s o n i c_i + son _i ,我们对于每个点尽可能多地从小到大删它的儿子。


Assassin Creed

Description

你是一个刺客,有把耐久度为 M M 的刀,你要杀死 N N 个敌人,其中杀死第 i i 个敌人需要消耗 A i A_i 点耐久度,但可以得到一把能杀死 B i B_i 个敌人的武器(不消耗自己的耐久度)。问最多可以杀死多少个敌人。以及在这个前提下,最少需要消耗的耐久度。

Solution

  1. 先杀一个 B i > 0 B_i > 0 A i A_i 最小的人,借刀杀掉所有 B i > 0 B_i > 0 的人,如果还有刀,就杀掉剩下 A i A_i 最大的人。最后用自己的刀把 A i A_i 尽可能小的一些人杀掉。但是还存在一种情况,对于 B i > 0 B_i > 0 的人,不用敌人的刀杀死他而用自己的刀就有可能杀掉更多的人。
  2. 可能 B i > 0 B_i > 0 的人 A i A_i 都非常大,所以可能只能杀 A i A_i 尽可能小的一些人。

打游戏

Description

Solution

先将 n n 个怪从小到大排序,然后依次打。如果场上最小怪的生命值为 1 1 时能放群攻,就放群攻,如果怪的个数 > 2 >2 能放群攻放群攻,如果只有两个怪且他们生命值 2 \ge 2 时从小到打能放重击放重击。


DFS Spanning Tree

Description

给出一个没有自环的有向图。这个图的前 n 1 n-1 条边构成这个图的一个以节点 1 1 为根节点的 dfs 树。T-Simple 环的定义是:至多有一条边不在这棵树上的环。至少在图上选中多少条边。才使得每个 T-simple 环都至少有一条边被选中。

Solution

题目给出了是 dfs 序的树,可以发现,除了树上的边就只有返祖边。每条非树边都相当于在 dfs 生成树上划定了一条深度单调的链,问题转化为最少染色多少条边,可以使每条链上都至少有一条边被染色

先考虑一个不在树上的子问题, 有一个序列,现在有 n n 个限制条件。第 i i 个限制是, L i L_i R i R_i 的这段区间内至少有一个位置被打标记。问至少要打几个标记。可以从左往右扫,对于每个没有标记的限制条件 x x 就贪心地在 R x R_x 打一个标记。

那么这个问题就是把数列改成了一棵树,把限制放在树上,直接树形 dp 即可。


乐曲创作

Description

给你一个 n n 个数的排列 a [ 1 n ] a[1 \sim n] ,设它有 m m 个逆序对。现在要求找出字典序大于原序列最小的排列,使它逆序对的个数也等于 m m

Solution

b b 为构造的数组,那么有一个 p p 满足 a 1 p 1 = b 1 p 1 a_{1 \sim p - 1} = b_{1 \sim p - 1} a p b p a_p \leq b_p 。最优的 b b 一定是在 p p 尽可能靠后的前提下, i b [ p + 1 , n ]   a i i \in b_{[p + 1,n]} \ a_{i} a i 1 a_{i-1} 尽可能小的前提下尽可能的小。

所以从后往前找到一个 p p ,首先满足他后面有至少一个比它大的数。其次,我们把一个数交换成比它大的最小的数,会造成多的逆序对,如果 [ p + 1 , n ] [p+1,n] 的数按照从小到大排列,那么 [ 1 , n ] [1,n] 的逆序对个数最少,在最少的情况下,逆序对总数还 > m > m ,那么我们就只能放弃这个 p p 去枚举之前的 p p 。否则,我们一定有策略让 [ 1 , n ] [1,n] 的逆序对总数 = m =m 。可以证明,对于第二个限制,只要 [ p + 1 , n ] [p+1, n] 中有至少一个逆序对,那么一定有策略让 [ 1 , n ] [1,n] 的逆序对总数 = m =m

确定 p p 后, b [ 1 , p 1 ] b_{[1,p - 1]} a [ 1 , p 1 ] a_{[1,p - 1]} 相同, b p b_p a [ p + 1 , n ] a_{[p + 1, n]} > a p >a_p 的最小的数,接下来要从 p p 往后做构造 b [ p + 1 , n ] b_{[p + 1,n]} 。我们找到了 p p ,那么已经搞定了 b b 的字典序 > a > a 的问题和无论如何安排数逆序对总数都 > m > m 的问题 ,对于 b [ p + 1 , n ] b_{[p + 1,n]} 的构造,要让越往前的位置安排的数尽可能的小,如果我们在 i b [ p + 1 , n ] a i i \in b_{[p + 1,n]} a_{i} 安排了一个 < a i <a_i 的数,那么逆序对总数会减少。如果 [ i + 1 , n ] [i+1,n] 按照从大到小排列,那么 [ 1 , n ] [1,n] 的逆序对个数最多,在最多的情况下,逆序对总数还 < m <m ,那么我们要在位置 i i 安排一个大一点的数。


Shop

Description

现在有 n n 个数 a i a_i 。有三种操作, a i = b a_i = b a i + b a_i + b a i × b a _i \times b ,其中 i i b b 为给定参数。现在给你 m m 以上个操作,你能从中最多选出 k k 个并自行安排顺序,要求操作完后 n n 个数的乘积最大。

Solution

可以发现先进行 a i = b a_i = b ,再进行 a i + b a_i + b ,最后进行 a i × b a_i \times b 是最优的。考虑将前两种操作转换成第三种。对于第一种操作通过 b a i b - a_i 转成第二种,第二种可以通过 ( a i + b ) a i \frac{(a_i + b)}{a_i} 求出倍率。然后全部成为操作三了,从大到小排序求。这样做并不违背之前的规律,因为乘法的顺序和乘在哪个 a i a_i 是没关系的。但是输出的时候一定要按照先赋值再加最后乘的顺序。值得一提的是,对于同一个数的赋值保留最大的。


Color a tree


修理牛棚 Barn Repair

Description

有一排共 n n 个牛棚,有的牛棚有牛。请你用不超 m m 块木板盖住有牛的牛棚,木板长度自定。求最小木板长度和。

Solution

逆向思维贪心。 用一个长度为 n n 的木板盖住所有的牛棚,可以发现盖了没有牛的牛棚,于是我们可以删一段木板,每删一段木板,木板数会多一个,所以可以删 m 1 m - 1 次木板。删木板根据贪心思想,删去长度要尽可能的长,但还不能将有牛的牛棚删掉。所以我们可以将所有的没有牛的牛棚找出来,将每个连续的一段的长度排序,从大到小删即可。


Bohater

Description

你需要打败 n n 只怪物。打败第 i i 只怪物需要消耗 d i d_i 点生命值,但怪物死后会掉落血药,使你恢复 a i a_i 点生命值。任何时候你的生命值都不能降到零及以下。求是否存在打怪顺序,使得你可以打完这 n n 只怪物而不死掉。

Solution

为了打更多的怪,我们想办法先回血,而且先回尽可能多的血,不过想先回血要先消耗生命值。那么将打怪消耗的血量从小到大排序,将能打的怪用一个堆维护,优先取出回血多的怪,打完一个怪后看看能不能加一些怪进堆。


护花

Description

n n 只牛,第 i i 头每分钟吃 d i d_i 朵花,可以让第 i i 头牛不吃花,但过 2 × t i 2 \times t_i 分钟后 才能让下一头牛不吃花,求牛最少吃多少花。

Solution

t i × 2 t_i \times 2 ,考虑相邻的两头牛交换顺序,第一头在第二头前面为 d 1 + d 2 × t 1 d_1 + d_2 \times t1 ,第二头在第一头前面为 d 1 × t 2 + d 2 d_1 \times t_2 + d_2 ,如果前式小于后式,那么第一头排在第二头前面,所以自定义比较函数排个序。


优惠券

Description

n n 本书,第 i i 本书花费 p i p_i 元,有 k k 张优惠券,一张优惠券可以让第 i i 本书降价到 c i c_i 元,求 m m 元能买多少书。

Solution

考虑选哪 k k 本书使用优惠券,对于两本书,如果一本用优惠券另一本直接买,若第一本书用优惠券,那么花费为 c 1 + p 2 c_1 + p_2 ,第二本书用优惠券花费为 c 2 + p 1 c_2 + p_1 ,如果前式小于后式,那么第一本书用优惠券,移项的话成了 p 1 c 1 < p 2 c 2 p_1 - c_1 < p_2 - c_2 ,所以将所有书按差值从小到大排序,选最小的 k k 本书用优惠券。还有钱的话将其他书的 p i p_i 从小到大排序依次买。


奶酪工厂

Description

n n 个星期,第 i i 个星期生产一个单位奶酪花费 c i c_i 分,多余生产的可以放在仓库,一个星期一个单位花 S S 分。第 i i 个星期需要 a i a_i 个单位的奶酪,求最小花费。

Solution

要么全部生产,要么全部从仓库取,所以在仓库屯有史以来最便宜的货,即为维护最小值,取货时比较一下两个情况。


均分纸牌

Description

n n 堆纸牌,每堆有若干张,总和为 n n 的倍数。每次可以将任意张牌从一堆移到与它相邻的一堆。求最少移动多少次才能让每堆纸牌数目相同。

Solution

显然相邻两堆只用移动一次。可以发现左右的移动可以归于一个左边向右边移动可正负张纸牌,所以求前缀和和纸牌平均数。从头扫,假设扫到了第 i i 张纸牌,如果第 i i 张纸牌需要向右移动当且仅当到 i i 的前缀和不等于 i × i \times 平均数。操作是可逆的,所以不存在第 n n 张牌不能向右移的尴尬。

扁鹊再世蔡徐坤

Linl

猜你喜欢

转载自blog.csdn.net/qq_39984146/article/details/107726746