种树(反悔贪心/修正结果)

题目

原题链接


问题描述

种树(反悔贪心/修正结果)_第1张图片


分析

最多选取 k k k个树坑,对于值为负数的坑不必考虑。
最直观的贪心就是从中选取前 k k k个值最大的坑,但考虑到选取位置的不可相邻,所以这样的选取方法无法保证最优解。

举例:当 k k k 2 2 2时,树坑价值序列为 [ 7 0 , 1 0 0 , 8 0 , 4 0 ] [7_0,10_0,8_0,4_0] [70,100,80,40],角标的 0 0 0表示尚可选取的合法位置。
若我们依据直观贪心,选 10 10 10,序列更新为 [ 7 1 , 1 0 1 , 8 1 , 4 0 ] [7_1,10_1,8_1,4_0] [71,101,81,40],只能再选择 4 4 4,总价值为 14 14 14
但根据我们的直观观察,可以知道应当选择 7 、 8 7、8 78,总价值为 15 15 15

通过这个例子,我们再引入反悔贪心的操作,若我们先选择了位置 i i i,即便 a i > a i − 1 & & a i > a i + 1 a_i>a_{i-1}\&\&a_i>a_{i+1} ai>ai1&&ai>ai+1,但有可能存在 a i < ( a i − 1 + a i + 1 ) a_i<(a_{i-1}+a_{i+1}) ai<(ai1+ai+1),假设我们根据之前的直观贪心思路处理完了 a i a_i ai后,接下来要处理一个合法位置 a j a_j aj a j < a i − 1 + a i + 1 − a i a_jaj<ai1+ai+1ai,也就是说此时选择 a j a_j aj不如对之前的 a i a_i ai进行修正,毕竟两者都需要耗费一次机会,我们自然会优先选择那个更好的。
a i − 1 + a i + 1 = a i − 1 + a i + 1 − ( a i ) + [ a i ] a_{i-1}+a_{i+1}=a_{i-1}+a_{i+1}-(a_i)+[a_i] ai1+ai+1=ai1+ai+1(ai)+[ai]
如果存在上述情况,而我们也确实将 a i a_i ai修正为了 a i − 1 + a i + 1 a_{i-1}+a_{i+1} ai1+ai+1,但是否存在对 a i + 1 a_{i+1} ai+1的修正?
如果对 a i + 1 a_{i+1} ai+1进行修正,也就是不选择 a i + 1 a_{i+1} ai+1,而选择 a i a_i ai a i + 2 a_{i+2} ai+2,同时, a i − 1 a_{i-1} ai1也要被迫修正,所以这一段的更新依然是多耗费一次机会,选择了 a i 、 a i − 2 与 a i + 2 a_i、a_{i-2}与a_{i+2} aiai2ai+2
a i + a i − 2 + a i + 2 = a i − 2 + a i + 2 − ( a i − 1 + a i + 1 − a i ) + [ a i − 1 + a i + 1 ] a_i+a_{i-2}+a_{i+2}=a_{i-2}+a_{i+2}-(a_{i-1}+a_{i+1}-a_i)_{}+[a_{i-1}+a_{i+1}] ai+ai2+ai+2=ai2+ai+2(ai1+ai+1ai)+[ai1+ai+1]
依照这个策略就可以对整体不断进行修正(反悔贪心)。

代码

#include 
typedef long long ll;
using namespace std;
#define fir(i, a, b) for (ll i = (a); i <= (b); i++)
#define rif(i, a, b) for (ll i = (a); i >= (b); i--)
const int N=5e5+5;
struct node{
	ll val,id;
	node(ll x,ll y){
		id=x;
		val=y;
	}
	bool operator < (const node b)const{return val<b.val;}
};
priority_queue<node>q;
ll n,k,vis[N],a[N],L[N],R[N],ans;
int main(){
	cin>>n>>k;
	fir(i,1,n){
		cin>>a[i];
		L[i]=i-1;
		R[i]=i+1;
		q.push({i,a[i]});
	}
	node tmp=node(0,0);
	while(k>0){
		while(vis[q.top().id])q.pop();
		if(q.top().val<=0)break;
		tmp=q.top();
		q.pop();
		k--;
		ans+=tmp.val; 
		vis[L[tmp.id]]=vis[R[tmp.id]]=1;
		q.push({tmp.id,a[tmp.id]=a[L[tmp.id]]+a[R[tmp.id]]-a[tmp.id]});
		L[tmp.id]=L[L[tmp.id]],R[L[tmp.id]]=tmp.id;
		R[tmp.id]=R[R[tmp.id]],L[R[tmp.id]]=tmp.id;
	}
	cout<<ans;
	return 0;
}

你可能感兴趣的:(贪心,贪心)