【胡诌学习笔记】某种反悔贪心

89 篇文章 0 订阅
30 篇文章 0 订阅

典例营

TJOI2013 拯救小矮人传送门 to luogu

沐目女未

对于所有跑出去了的人,让 ( a + b ) (a{+}b) (a+b) 小的先出去更优。 exchange argument \text{exchange argument} exchange argument 易证。

那么按照 ( a + b ) (a{+}b) (a+b) 排序。如果一个人能够出去,就出去;否则,考虑某个已经出去的人回到坑里,而当前人出去,让垫底的 ∑ a \sum a a 最大。所以维护已经出去的人关于 a a a 的大根堆即可。

核心代码:这里 i d id id 就是按照 ( a + b ) (a{+}b) (a+b) 排序后的结果,而 p q pq pq i n t \tt int int 类型的大根堆。

	int ans = 0; long long bottom = 0;
	for(int i=1; i<=n; ++i) bottom += a[i];
	for(int i=1; i<=n; ++i){
		if(bottom+b[id[i]] >= H){
			++ ans, bottom -= a[id[i]];
			pq.push(a[id[i]]);
		}
		else if(!pq.empty() && a[id[i]] < pq.top()){
			bottom += pq.top(); pq.pop();
			bottom -= a[id[i]]; pq.push(a[id[i]]);
		}
	}

知识桥

d p \tt dp dp 转移的条件是关于 d p \tt dp dp 值(或者只涉及参数)的简单大小比较,且值的转移是加法时, d p \tt dp dp 值可能会是个凸函数,此时可以用 闵可夫斯基和 维护。

就例题而言,设 f ( i , j ) f(i,j) f(i,j) 为,已经考虑了前 i i i 个人,跑出去了 j j j 个人,跑出去的人的 ∑ a \sum a a 最小是多少。有转移
f ( i + 1 , j ) = min ⁡ { f ( i , j ) ,    f ( i , j − 1 ) + a i + 1 } ( s u m a − f ( i , j − 1 ) + b i + 1 ⩾ H ) f(i{+}1,j)=\min\{f(i,j),\;f(i,j{-}1){+}a_{i+1}\}\quad(sum_a-f(i,j{-}1)+b_{i+1}\geqslant H) f(i+1,j)=min{f(i,j),f(i,j1)+ai+1}(sumaf(i,j1)+bi+1H)

注意这个 d p \tt dp dp 式并不正确,因为它假定了跑出去的人的编号是从小到大的,因此需要 s o r t \tt sort sort 。但这个做法的好处是:马上我们就可以直接看出,依据什么进行排序,又需要用堆维护什么。也就是机械化的反悔贪心。

将状态视作 ( j , f ( i , j ) ) (j,f(i,j)) (j,f(i,j)) 这样一个点,那么转移的本质是 ( 0 , 0 ) , ( 1 , a i ) (0,0),(1,a_i) (0,0),(1,ai) 两个点构成的凸包,与 d p \tt dp dp 值的凸包作闵可夫斯基和。注:事实上我们并没有证明 d p \tt dp dp 值构成凸包,但我们可以坚信之。

转移的要求是 f ( i , j − 1 ) + a i + 1 ⩽ s u m a − H + a i + 1 + b i + 1 f(i,j{\rm-1})+a_{i+1}\leqslant sum_a-H+a_{i+1}+b_{i+1} f(i,j1)+ai+1sumaH+ai+1+bi+1,注意左侧必须是结果的式子,即直接更新 f ( i + 1 , j ) f(i{\rm+}1,j) f(i+1,j) 的值。然后我们要 让限制条件越来越宽松,故按照 ( a i + b i ) (a_i{+}b_i) (ai+bi) 从小到大排序。

找到使得 f ( i , j ) f(i,j) f(i,j) 有定义的最大的 j j j,记为 j 0 j_0 j0 。如果 f ( i , j 0 ) f(i,j_0) f(i,j0) 满足转移条件,那就是完整的闵可夫斯基和,直接将这个斜率 a i a_i ai 加入堆;否则考虑 f ( i , j 0 ) − f ( i , j 0 − 1 ) f(i,j_0)-f(i,j_0{-}1) f(i,j0)f(i,j01) a i a_i ai 的大小关系:

  • 如果 a i a_i ai 不小于它,又因为这是凸包上最大的斜率,故 a i a_i ai 无法进行任何更新。
  • 如果 a i a_i ai 比它小,那么 a i a_i ai 至少足以更新 f ( i , j 0 ) f(i,j_0) f(i,j0),所以去掉 f ( i , j 0 ) f(i,j_0) f(i,j0) 后进行闵可夫斯基和即可。——在代码实现上,体现为将优先队列的堆顶删除,将 a i a_i ai 插入。

为什么 a i a_i ai 足以更新 f ( i , j 0 ) f(i,j_0) f(i,j0) 呢?这就涉及到上面的排序了。限制条件在变宽松,所以 d p \tt dp dp 值变小的转移总是合法转移

最后,它为什么是正确的。因为 f f f随着转移进行而偏离目标,如 f f f min ⁡ \min min j j j 越大 f f f 就越大。然后,两个连续被选的物品,显然前者拥有更差的限制是最好的(否则也可以调整为这种情况)。

训练营

JSOI2007 建筑抢修传送门 to luogu

i i i 个建筑修好 j j j 个的最小时间花费 f ( i , j ) ← f ( i − 1 , j − 1 ) + T 1 ( i ) ⩽ T 2 ( i ) f(i,j)\leftarrow f(i{\rm-}1,j{\rm-}1)+T_1(i)\leqslant T_2(i) f(i,j)f(i1,j1)+T1(i)T2(i),按照 T 2 T_2 T2 排序后维护 T 1 T_1 T1 大根堆。

CF1251E2 Voting传送门 to CF

稍微有所改变,因为转移条件跟人数挂钩,应该把人数设为 d p \tt dp dp 值。前 i i i 人都投了票,省下了 j j j 元,最小化倒戈的人数量。假设该人首个倒戈,有转移 f ( i , j ) ← f ( i − 1 , j − p i ) + 1 ⩽ n − m i f(i,j)\leftarrow f(i{\rm-}1,j{\rm-}p_i)+1\leqslant n-m_i f(i,j)f(i1,jpi)+1nmi 。这里凸包的斜率成为了 1 p i 1\over p_i pi1,维护 p i p_i pi 的小根堆。

美术馆起火:在 d i d_i di 时刻前,分配连续的 b i b_i bi 时长以获得 v i v_i vi 价值,最大化之。

f ( i , j ) ← f ( i − 1 , j − v i ) + b i ⩽ d i f(i,j)\gets f(i{-}1,j{-}v_i)+b_i\leqslant d_i f(i,j)f(i1,jvi)+bidi,按照 d i d_i di 排序后维护 b i v i b_i\over v_i vibi 的堆。

补充信息

另一种反悔贪心,用堆维护,形如 ∑ f i ( x i ) \sum f_i(x_i) fi(xi) ∑ x i = k \sum x_i=k xi=k 时的最值,事实上是归纳法容易证明的。即,改变的部分不能有可以划分成权值相等的子集。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值