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 天后,必须再次回到零持股状态 所以卖出。
但是对于这一天出了,卖出 和 不动 还有买入。这时可以注意到如果在 不动 的基础上再减去当天的价格就转换为了 买入 。
所以如果进 卖出 后在堆中加入两次否则加入一次
浙公网安备 33010602011771号