2026.09.08 反悔贪心

啥是反悔贪心

反悔贪心就是可以 反悔 的贪心。最基础的方法就是用 堆(优先队列) 去 反悔

看例题 T1 Work Scheduling G

先想贪心策略,可以按 \(D_i\) 从小到大排。

很明显有问题,比如当时间过了但这个工作的利润比之前的高,于是我们可以开始 反悔 了。

我们从之前做过的工作中寻找利润最低(前提是这个工作的利润比它高)的直接 反悔 改成这个这个更划算的操作。

code:

#include<bits/stdc++.h>
using namespace std;
priority_queue<long long> q;
int n;
struct work{
	long long d,p;
};
bool cmp(work a,work b){
		if(a.d==b.d)return a.p>b.p;
		return a.d<b.d;
}
work a[100010];
long long sum;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].d>>a[i].p;
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++){
		if(q.size()<a[i].d/*可以做此操作*/){
			q.push(-a[i].p);
			sum+=a[i].p;
		}else if(-q.top()<a[i].p/*判断此操作的贡献是否最低*/){
				sum+=q.top()+a[i].p;//删去贡献最低的
				q.pop();q.push(-a[i].p);
		}
	}
	cout<<sum;
	return 0;
}

对,这个代码很优美。(bushi

我们其实还有一种思路,我们可以看到工作就做不关有没有时间。让后再删去最差的工作使得这个工作可以完成。

这样就可以省去一些代码。

code:

#include<bits/stdc++.h>
using namespace std;
priority_queue<long long> q;
int n;
struct work{
	long long d,p;
};
bool cmp(work a,work b){
		if(a.d==b.d)return a.p>b.p;
		return a.d<b.d;
}
work a[100010];
long long sum;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].d>>a[i].p;
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++){
		sum+=a[i].p;
		q.push(-a[i].p);//做此操作
		while((q.size()!=0)&&q.size()>a[i].d){//如果不合法则删去贡献最低的使得合法
			sum+=q.top();q.pop();
		}
	}
	cout<<sum;
	return 0;
}

T2 Potions (Hard Version)

也是板子题。

code:

#include<bits/stdc++.h>
using namespace std;
priority_queue<int> q;
int n;
long long cnt;
long long sum;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		int a;
		cin>>a;
		sum+=a;
		cnt++;
		q.push(-a);
		while((q.size()!=0)&&sum<0){
			sum+=q.top();q.pop();
			cnt--;
		}
	}
	cout<<cnt;
	return 0;
}

T3 Ignore Operations

看似和反贪没有一点关系,其实只要稍微转换一下。

先注意力惊人,如果有 \(1\) 操作 则前面的操作等于没做。于是倒序贪心。

对,这就和T2很像了

T4 Buy Low Sell High

雀食有趣。如果你想到了这个 trick 那就很简单了。

首先考虑前面有买入的,那为了 经过 N 天后,必须再次回到零持股状态 所以卖出。

但是对于这一天出了,卖出 和 不动 还有买入。这时可以注意到如果在 不动 的基础上再减去当天的价格就转换为了 买入 。

所以如果进 卖出 后在堆中加入两次否则加入一次

posted on 2026-09-09 23:05  zzyycc2013  阅读(12)  评论(0)    收藏  举报