贪心 & 倍增 & 构造
贪心 !贪心!贪心!
倍增!倍增!倍增!
构造!构造!构造!
CF1516D Cut
一个长度为 \(n\) 的序列,每次询问 \([l, r]\) 最少划分成多少段使得每一段的乘积等于他们的 \(\operatorname{lcm}\)。
不难发现题目给出的限制就是每一段的数两两互质,而且总是贪心地选择最靠右的满足条件的,所以一个位置向右延伸的长度是固定的。
可以双指针求出每个点向右延伸的长度,然后预处理倍增,每次询问的时候从 \(l\) 开始跳就行了。
P3295 [SCOI2016]萌萌哒
一个长度为 \(n\) 的序列, \(m\) 个限制条件 \(l_1, r_1,l_2,r_2\),保证长度相同,意思为 \(s[l_1..r_1]\) 与 \(s[l_2..r_2]\) 相同, 求满足所有条件的数。
暴力直接可以用一个并查集维护,假设不同的连通块有 \(k\) 个,则答案就是 \(9\times 10^{k-1}\),这样询问是 \(O(n^2)\),而查询只是 \(O(n)\) 的,这启发我们平衡复杂度。
考虑倍增, 对于每个点维护 \([i,i+2^k-1]\) 的并查集,那么查询可以直接跳,那么怎么求答案呢 ?
以 \(k\) 从大往小合并并查集,若一个点 \(x\) 它的根不是它自己的话, 就把 \(x\) 的左右儿子和根的左右儿子合并即可。
不错的思路。
CF1175E Minimal Segment Cover
给定 \(n\) 个线段 \([l_i,r_i]\),\(m\) 次询问 \(x,y\),求至少选多少个线段使得它们的并包含 \([x,y]\)。
首先对线段按右端点 \(r\) 排序, 去掉完全被包含的线段, 求出它的可以向右延伸的端点是 \(p\),倍增计算。跟第一个题差不多。
P1084 [NOIP2012 提高组] 疫情控制
一棵树, 边有边权,有 \(m\) 个军队最开始在点 \(p_i\) ,每一个军队可以移动到一棵非根的子树上把这棵子树封锁, 消耗的时间为走过的边权和, \(m\) 个军队可以同时移动, 求最少的时间封锁所有叶子节点。
首先二分答案, 看是否能在 \(\leq x\) 的时间内完成, 我们考虑如下贪心策略 :
1.若一个点可以走到根,先让它走到根,并把它们剩余时间从小到大排序。
2.若不能, 因为越往上的点能封锁的点是越多的,直接把这个点提到它所能走到的最上端的点。
那么此时已经有一些点被封锁。如果对于一个点, 在根方向的那个父亲没有被封锁的话, 那么还是让它回去封锁它的父亲。
再把所有 1 的所有未封锁的儿子按边权从小到大排序,与剩余的点一一匹配,若能匹配完则有解。
需要注意的是当一个点的所有子树都被封锁后这个点也被封锁了。 细节多多多多。
CF1251E2 Voting (Hard Version)
一共有 \(n\) 个选民,你可以付出 \(p_i\) 的代价让第 \(i\) 个选民为你投票,或者,在为你投票的人数达到 \(m_i\) 时,他会主动为你投票而不用你付出任何代价。
问得到所有选民投票的最小代价。
神仙贪心题。
首先这种最小代价肯定要对于一维排序,不妨以 \(m_i\) 降序排序, 在考虑一段相同的 \(m\) 时, 我们可以认为 \(m_i > m\) 的 \(i\) 已经被说服了,其中有 \(cnt\) 个人是花费代价购买的,小于 \(m\) 的个数有 \(k\) 个, 那么总的花费钱的个数是 \(cnt+k\),若 \(cnt + k \geq m\),则这些点都可以免费选。
否则我们把这些点加入小根堆里面, 每次贪心的找出最小的 \(p_i\) 累加答案即可。