凸贪心杂题
P11328
贪心策略的发现的通用方法:假定最优解集合,再微调研究
很明显我们应该使用邻项交换法,假设选定了按照什么顺序参加比赛,并且参加的每一场都获得了徽章,那么考虑先操作 \(i\) 再操作 \(j\) 合法,而先操作 \(j\) 非法的条件是:
首先,必然有 \(now\le L_i,now\le L_j\),只需要看剩下的条件:
因此按 \(L+X\) 升序操作最优。
然后,考虑获得最多的徽章,这是一个经典问题。
从头开始扫,如果可以直接用 \(L_i\),那么直接用,否则找到有效的比赛里 \(X\) 最大的扔掉,换成 \(X_i\)(如果 \(X_i\) 更小)。
证明是容易的,假设换了 \(j\),也就有:
那么将 \(j\) 同时刻替换为 \(i\) 不会变差,一定合法。
JOISC2018 J
很经典的贪心结论,需要注意的是一定要设 \(0,n+1\) 为 \(\infty\),否则不能满足每次至少增加一个的条件。
P14265
枚举一下首尾颜色就变成了上个题,方案输出可以通过区间 \(\oplus 1\) 打标记实现。
注意细节。
CF1799 F
显然需要先除再减,对同一个数字。
不妨设用了除减,除法,减法,没用的数字个数分别是 \(a,b,c,d\),那有:
并且,同一类操作用数字较大的一定比数字小的更好,因此我们就知道了 \(a,d\) 分别取数字从大到小排序后的前缀和后缀。
不妨枚举 \(a\)。
那么考虑单个除法和减法怎么分?
对于 \(val>2b\) 而言,除法不劣于减法,而对于 \(val<2b\) 而言都是除法劣势。
因此可以知道,我们会首先做除法,然后在一个分界点做减法,最后剩下的数字做除法。
事实上最优分界点可以算出来,大概可以做到线性或者一个 \(\log\),但这里 \(n\) 只有 \(5000\),暴力枚举,借助前缀和即可 \(O(1)\) 计算。
AT-jag2017autumn_j
首先可以找到一些性质(虽然没有用)。
如果我一个都不生产,一定找人要,如果我只生产一个,一定自己用,如果我生产两个,一定支援他人。
因此这是个最小费用流问题,由此原问题具有凸性。
暴力建图是 \(O(n^2)\) 的图,但是可以做前后缀优化建图,图就只有 \(O(n)\) 条边了。
这启发我们做 \(dp\)。
不妨设 \(dp_{i,j}\) 为处理了 \([1,i]\),当前的流量为 \(j\)(正负号代表流向)。
转移就是:
这是在做什么?
先做一个 \(dp'_{j}=dp_{j}+|j|d_i\),然后再往右平移一格,然后就变成了与 \(\lbrace 0,g_i,2g_i\rbrace\) 做 \((\max,+)\) 卷积。
那么可以考虑维护闵可夫斯基和,也就是维护 \(dp\) 值的差分,显然这是下凸壳。
我们需要做的?
- 维护最低点,也就是 \(0\) 的所在,支持平移。
- 支持 \(+|j|d_i\),也就是正负分离,\(\le0\) 与 \(>0\) 分开。
- 动态插入,维护有序结构
可以使用对顶堆,那么几个操作分别是:
- 往右平移一格:从\(\le 0\) 的堆里找最大值扔进 \(>0\) 的堆。
- 加 \(|j|d_i\),就是一个打标记的事情,维护左右堆分别的标记即可,左减右加。
- 动态插入,直接扔进堆里再平衡就行了,记得扔两次。
最低点的值是好维护的。
CF436 E
考虑 \(i\to i+1\),有四个策略:
- \(0\to 1\)
- \(1\to 2\)
- \(2\to 1,0\to 2\)
- \(1\to 0,0\to 2\)
用五个优先队列分别维护即可。
第二个做法是注意到下标 \(\mod 2\) 是凸的,因此考虑 \(i\to i+2\)。
CF335F
这题的题解都在写什么鬼
从高往低做
假设现在买了 \(x\),附赠了 \(y\),现在在处理值为 \(z\) 的,\(y\) 是附赠品里最便宜的。
-
如果买下 \(y\),就可以送两个 \(z\),代价是 \(y\)
-
否则直接买下两个 \(z\),赠送两次白嫖机会
那么就有 -
\(2z>y\) 时,买 \(y\) 来换会更优秀,这相当于是 \(y\) 和买 \(y\) 的那个元素同时提供了两次白嫖机会
-
与此同时,需要注意到,如果直接买两个 \(z\),也能会后续提供两次白嫖机会,因此等效为额外买了一个 \(2z-y\) 的物品
讨论一下:
-
只有一个 \(z\)
- \(y\ge z\) 肯定只有直接买了。\(y\) 仍然是白嫖物品。
- \(y<z\) 买下 \(y\),还能给更小的值白嫖一个,这时候去掉 \(y\),新的白嫖物品是 \(z\)。
综上,代价是 \(\min(z,y)\)。
-
有不止一个 \(z\)。
-
\(y<z\)
肯定买下 \(y\),白嫖两个 \(z\),代价 \(y\)。
那么白嫖物品就除掉 \(y\),加入两个 \(z\)。
\(y\) 在此刻消耗掉是最优的决策(白嫖了最多的 \(2z\))。
-
\(y< 2z\)
买下 \(y\) 显然更划算,这时候白嫖物品是两个 \(z\)。
直观的想法是我们加入两个 \(z\) 作为新的白嫖物品,但这是错误的。
注意到,我们每次消耗白嫖物品实质上是要多出两个白嫖额度,这一步操作以后我们要多出两个白嫖额度,就只剩下几个操作:
-
买下一个 \(z\)。
-
买下两个 \(z\),提供两个白嫖额度,\(y\) 就不用买了,代价是 \(2z-y\)。
注意到 \(z\le y<2z\implies 2z-y\le z\),也就是一定会先买两个 \(z\) 而撤掉买 \(y\) 的决策(后续买也不迟),也即买一个 \(z\) 这种事情不可能发生。
因此,我们实际上为未来有两个决策,先执行 \(2z-y\),再执行 \(y\)。
所以这相当于是两个新的白嫖物品。
-
-
\(y\ge 2z\)
显然应当直接买,不消耗\(y\)。
-
因此可以用优先队列维护这个贪心过程。
P8175
假定我们已经知道了我们需要买哪些糖果,如何走才能够保证拿完?
一个很自然的观察是我们从左往右拿糖果去消耗,因为从右往左只会让左边的限制更为严格。
首先,在同一位置的糖果,在取最后一个之前,一定是取了之后去最近的空地消耗。
不妨设 \(d_i\) 为商店 \(i\) 距离其最近的空地距离。
取最后一个之后,有两个决策:
- 还是去最近的空地再返回
- 去下一个商店,路上如果有空地就直接消耗了。
- 去下一个商店的右侧的空地(中间没有空地),再回到下一个商店去取。
不妨设 \(pre,suf\) 为商店 \(i\) 左右最近空地距离,\(nxt\) 为下一个商店。三个策略的代价分别是:
不妨记这个值是 \(f_i\),那么我们其实就已经明白代价了。
如果提前去掉走路的代价 \(nxt_i-i\)(因为这段路是必须要走的)。
问题就转化为了,我们从左往右取商品,在商店 \(i\) 的代价是这样的:
- 取首个商品的代价为 \(f_i\),保证 \(f_i\le d_i\)。
- 后续每个商品 \(d_i\) 块。
我们需要满足,对于每个 \(i\),除掉最后一个购买的商品的话(你可以拿在手上跑去卖掉,只要抢先买下就行)在所有商店 \(j\le i\) 买的商品总值不超过 \(i-1\)。注意这里的最后一个买指的是 \(f_i\)。
这可以使用反悔贪心解决,我们维护一个堆,里面放我们所有的买下的糖果的代价。
在走到商店 \(i\) 时:
-
首先尽可能买 \(d_i\),直到首次超限。
超限也可以考虑把之前更贵的删了换成我。
因为有 \(f_i\le d_i\),所以对于一个商店的撤销,一定先撤普通商品再撤这个特殊商品。
-
然后尽可能买一个 \(f_i\),策略和上面一样,如果买不了就说明上面也一个没买。
考虑分析一下复杂度。
由于 \(\sum d\) 是 \(O(n)\) 级的,因此 \(d,f\) 合起来只有 \(O(\sqrt n)\) 种取值。
而一个值最多被插入和撤销优先队列 \(O(\frac{n}{i})\) 次,并且只能被更小的值替换。
因此每个值至多在优先队列里变动(增删) \(O(\frac{n}{i})\) 次。
所以优先队列的插入删除不超过 \(O(\sum \frac{n}{i})=O(n\ln n)\) 次,因此复杂度不超过 \(O(n\log n\ln n)\)。
ABC363G
这太板了。
首先考虑原问题如何解决,这是一个经典贪心问题:
将所有任务按照截止时间 \(D_i\) 排序,用优先队列维护当前所选的任务。
从头开始扫描:
- 如果没到截止时间,直接将 \(P_i\) 加入优先队列。
- 否则观察优先队列里收益最低的是否比我低,如果比我低就拿我去替换。
让我们观察一下,这是在做什么,如何能够支持单修。
首先,由于需要排序,我们定然是要按照 \(D\) 为轴建立数据结构的。
然后考虑一个任务的影响。
假定我现在已经决定了当前最优的选择,现在加入了一个任务。
- 首先假装我选中这个任务。
- 如果现在合法,那自然最优。
- 否则找到最劣的任务,使得删掉它可以重新合法。
删除是同理的:
- 如果删的不在最优决策了,不管。
- 否则,观察有哪些任务可以加入决策集合,找最优的加入。
显然,决策集合的变动最多是 \(O(1)\) 的。
那么如何判断合法性?根据Hall定理:
- 对于任意时间 \(D\),截止时间 \(\le D\) 的被执行任务个数 \(\le D\)。
那么线段树初始化节点 \(i\) 权值为 \(i\),每次执行一个任务,就将 \([D_i,n]\) 减一。
只要全局最小值非负就合法。
那么上述就可以通过模拟实现了,只需要维护区间内尚未加入决策集合的最大权值,加入决策集合的最小权值,支持查找最左侧 \(-1\),最右侧 \(0\),然后支持区间加减即可。

浙公网安备 33010602011771号