专项:反悔贪心
CF865D#
题意:给定股票每天的价值,一天只可以买入一股或卖出一股,求
错误的贪心:在第
用小根堆维护。
rep(i, 1, n) {
int x; cin >> x;
if(!q.empty() && q.top() < x) {
ans += x - q.top();
q.pop();
}
q.push(x);
}
对于
考虑反悔。
什么叫反悔?也就是把第
-
如果第
天选了 且第 天选了 ,由于 ,等同于第 天选了 ,相当于撤销了 的影响。
仅这样处理是不够的。
此时第 天的股票已经踢出队列,但实际上还没被卖出,有可能对答案有贡献的,不能踢出。 -
如果第
天选了 ,上述代码中的push(x)
实际上是把一个待反悔的 加入队列。
只需要再push(x)
一次,将 加入队列。
rep(i, 1, n) {
int x; cin >> x;
if(!q.empty() && q.top() < x) {
ans += x - q.top();
q.pop();
q.push(x);
}
q.push(x);
}
P2949 [USACO09OPEN] Work Scheduling G#
题意:
贪心:按截止时间排序,能做就做。
反悔:不能做时,如果前面存在小于当前价值的元素,撤销操作,更新贡献。
小根堆维护已经做了的所有价值,用堆的大小表示当前时间。
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int n; cin >> n;
vector<pair<int, int>> a(n);
for(auto &[x, y] : a) cin >> x >> y;
ranges::sort(a);
priority_queue<ll, vector<ll>, greater<ll>> q;
for(auto &[x, y] : a) {
if(x > q.size()) {
q.push(y);
}
else if(y > q.top()) {
q.pop();
q.push(y);
}
}
ll ans = 0;
while(!q.empty()) {
ans += q.top();
q.pop();
}
cout << ans;
return 0;
}
P4053 [JSOI2007] 建筑抢修#
题意:
贪心:按截止时间排序,能做就做。
反悔:不能做时,如果前面存在
维护当前时间
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int n; cin >> n;
vector<pair<int, int>> a(n);
for(auto &[ed, len] : a) cin >> len >> ed;
ranges::sort(a);
priority_queue<int> q;
ll t = 0;
for(auto &[ed, len] : a) {
if(t + len <= ed) {
t += len;
q.push(len);
}
else {
if(len < q.top()) {
t += -q.top() + len;
q.pop();
q.push(len);
}
}
}
cout << q.size();
return 0;
}
P2107 小Z的AK计划#
肯定是顺着走一遍最优,每个点抉择选或不选。
贪心:能选就选。
反悔:如果已经选过的点中存在思考时间大于当前位置,撤销操作。
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
ll n, m; cin >> n >> m;
vector<pair<ll, ll>> a(n);
for(auto &[pos, val] : a) cin >> pos >> val;
ranges::sort(a);
priority_queue<ll> q;
ll x = 0;
for(auto &[pos, val] : a) {
if(pos + x + val <= m) {
x += val;
q.push(val);
}
else if(!q.empty() && val < q.top()){
x += val - q.top();
q.pop();
q.push(val);
}
}
cout << q.size();
return 0;
}
CF3D Least Cost Bracket Sequence#
如果
维护
如果
priority_queue<pair<int, int>> q;
string s;
ll tp, ans;
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
cin >> s;
for(int i = 0; auto ch : s) {
if(ch == '(') {
++ tp;
}
else {
-- tp;
if(ch == '?') {
int L, R; cin >> L >> R;
ans += R;
s[i] = ')';
q.emplace(R - L, i);
}
}
if(tp < 0) {
if(q.empty()) break;
tp += 2;
ans -= q.top().first;
s[q.top().second] = '(';
q.pop();
}
++ i;
}
if(tp == 0) cout << ans << '\n' << s;
else cout << -1 << '\n';
return 0;
}
CF730I#
先用编程能力最大的
分类讨论:
- 招人:从剩余学生中,选择运动能力最大的。
- 挖人:从编程队中挖一名【运动能力减编程能力】最大的学生到运动队,然后编程队再招人,从剩余学生中,选择编程能力最大的。
上面这两种方法,谁能让能力总和变得更大,就用哪种方法。重复执行 次。
#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); ++ i)
#define per(i, a, b) for(int i = (a); i >= (b); -- i)
#define pb emplace_back
using namespace std;
using ll = long long;
constexpr int N = 3e3 + 5;
int n, p, s, a[N], b[N], ans;
struct programming {
int i;
bool operator < (const programming &o) const {
if(b[i] - a[i] != b[o.i] - a[o.i]) return b[i] - a[i] > b[o.i] - a[o.i];
return i > o.i;
}
};
struct remain_p {
int i;
bool operator < (const remain_p &o) const {
if(a[i] != a[o.i]) return a[i] > a[o.i];
return i > o.i;
}
};
struct remain_s {
int i;
bool operator < (const remain_s &o) const {
if(b[i] != b[o.i]) return b[i] > b[o.i];
return i > o.i;
}
};
set<programming> se;
set<remain_p> rp;
set<remain_s> rs;
set<int> ss;
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
cin >> n >> p >> s;
for(int i = 1; i <= n; ++ i) cin >> a[i];
for(int i = 1; i <= n; ++ i) cin >> b[i];
for(int i = 1; i <= n; ++ i) {
rp.insert({i});
rs.insert({i});
}
for(int i = 1; i <= p; ++ i) {
int x = rp.begin() -> i;
se.insert({x});
rp.erase({x});
rs.erase({x});
}
for(auto [i] : se) ans += a[i];
for(int i = 1; i <= s; ++ i) {
int x = 0, y = 0;
x = b[rs.begin() -> i];
y = b[se.begin() -> i] - a[se.begin() -> i] + a[rp.begin() -> i];
if(y < x) {
ans += x;
int j = rs.begin() -> i;
rp.erase({j});
rs.erase({j});
ss.insert(j);
}
else {
ans += y;
int j = se.begin() -> i;
se.erase({j});
ss.insert(j);
j = rp.begin() -> i;
se.insert({j});
rp.erase({j});
rs.erase({j});
}
}
cout << ans << '\n';
for(auto [i] : se) cout << i << ' '; cout << '\n';
for(auto i : ss) cout << i << ' ';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?