反悔贪心
P2949 Work Scheduling G:有 个事件,每个事件有一个截止日期和收益,每个时间点可以完成一个事件,求最大收益和。
可以开一个堆来维护当前选定的所有事件,按照截止日期排序。
显然所有截止日期靠后的事件也可以在前面完成,所以满足反悔。
每一次如果选定事件数小于截止日期就可以直接放进堆里面,更新答案。
否则,如果堆顶元素(选定的所有事件中的最小收益)小于当前事件收益就可以弹掉堆顶,放进当前事件,更新答案。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
int n, res; struct Node {
int d, val;
inline bool operator <(const Node &X) const {
return val > X.val;
}
} b[N]; priority_queue <Node> q;
inline bool cmp(Node x, Node y) { return x.d < y.d; }
signed main() {
ios_base::sync_with_stdio(false); cin.tie(0), cout.tie(0);
cin >> n; for (int i = 1; i <= n; ++i) cin >> b[i].d >> b[i].val;
sort(b + 1, b + 1 + n, cmp);
for (int i = 1; i <= n; ++i) {
if (q.size() < b[i].d) q.push(b[i]), res += b[i].val;
else if (q.top().val < b[i].val)
res -= q.top().val - b[i].val, q.pop(), q.push(b[i]);
}
cout << res << endl;
return 0;
}
CF865D Buy Low Sell High:每天股票有一个价格,每天可以买入 / 卖出一支股票,求最大收益和。
同样地,建立一个小根堆,每次把买入的股票加进去然后反悔即可。
如何知道加了哪些股票呢?很简单,只要把每一支股票都视为加入,如果要反悔就统计答案。
最后留在堆里面的就不用管了。
有一个小 trick。由于最后产生的收益为卖出 买入,所以可以拆贡献。
也就是说,我们并不关心中间的处理过程,我们只关心最后这一对买入 - 卖出产生的收益。
假设买入花费 代价,第一次发现可以卖出获得收益 ,那么净收益为 。此时将 弹出, 加入序列。
假设现在又有一个卖出的机会 ,找到堆顶 ,那么净收益为 。
我们发现,此时产生的收益等价于将 和 进行配对,净收益为 。
也就是说,可以忽略这个 的存在,当作中间变量即可。
除此之外,由于最终收益为 卖出 买入,所以我们也不关心它们是怎样配对的。
只需要知道每一次反悔的 即可。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3e5 + 10; int n, res;
priority_queue <int, vector <int>, greater <int> > q;
signed main() {
ios_base::sync_with_stdio(false); cin.tie(0), cout.tie(0);
cin >> n; for (int i = 1, x; i <= n; ++i) {
cin >> x; q.push(x);
if (q.top() < x) res += x - q.top(), q.pop(), q.push(x);
}
cout << res << endl;
return 0;
}
CF13C Sequence:对于一个数列,每次可以把某一位 或 ,求使得整个序列单调非降的最小操作数。
贪心地想,使得操作次数最少可以转化为改变的元素最少,即改动后的数组内一定可以全为原数组内的元素。
令原数组为 ,重排后的数组为 。
考虑设 表示当前处理到 ,以 结尾的最小操作数。
那么有 。
对于每一个 ,可以发现,到某个 开始往后的值都变得一样。
也就是说有大量无用状态。
那么可以考虑贪心(见 P4597 Sequence 加强版)。
受到前面 答案的启发,贪心地想可以发现,被更改成为 的元素越小,它就越容易成为一个单调非降的序列。
考虑反悔,即新建一个大根堆,每一次提出选择过的最大元素。
如果当前元素比大根堆顶更小,即不满足非降,就踢掉原来的堆顶,放上当前元素成为堆顶,更新答案。
答案更新加上两者差即可,同理于之前求 和 求差的过程。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e3 + 10;
int n, res;
signed main() {
ios_base::sync_with_stdio(false); cin.tie(0), cout.tie(0);
cin >> n; priority_queue <int> q;
for (int i = 1, x; i <= n; ++i) {
cin >> x; q.push(x);
if (x < q.top()) res += q.top() - x, q.pop(), q.push(x);
}
cout << res << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现