反悔贪心

P2949 Work Scheduling G:有 n 个事件,每个事件有一个截止日期和收益,每个时间点可以完成一个事件,求最大收益和。

可以开一个堆来维护当前选定的所有事件,按照截止日期排序。

显然所有截止日期靠后的事件也可以在前面完成,所以满足反悔。

每一次如果选定事件数小于截止日期就可以直接放进堆里面,更新答案。

否则,如果堆顶元素(选定的所有事件中的最小收益)小于当前事件收益就可以弹掉堆顶,放进当前事件,更新答案。

#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。由于最后产生的收益为卖出 买入,所以可以拆贡献。

也就是说,我们并不关心中间的处理过程,我们只关心最后这一对买入 - 卖出产生的收益。

假设买入花费 x 代价,第一次发现可以卖出获得收益 y>x,那么净收益为 yx。此时将 x 弹出,y 加入序列。

假设现在又有一个卖出的机会 z>y,找到堆顶 y,那么净收益为 zy

我们发现,此时产生的收益等价于将 xz 进行配对,净收益为 (zy)+(yx)=zx

也就是说,可以忽略这个 y 的存在,当作中间变量即可。

除此之外,由于最终收益为 卖出 买入,所以我们也不关心它们是怎样配对的。

只需要知道每一次反悔的 Δans 即可。

#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:对于一个数列,每次可以把某一位 +11,求使得整个序列单调非降的最小操作数。

贪心地想,使得操作次数最少可以转化为改变的元素最少,即改动后的数组内一定可以全为原数组内的元素。

令原数组为 a,重排后的数组为 b

考虑设 dpi,j 表示当前处理到 ai,以 bj 结尾的最小操作数。

那么有 dpi,j=min{dpi,j1,dpi1,j+|aibj|}

对于每一个 i,可以发现,到某个 j 开始往后的值都变得一样。

也就是说有大量无用状态。

那么可以考虑贪心(见 P4597 Sequence 加强版)。

受到前面 dp 答案的启发,贪心地想可以发现,被更改成为 bj 的元素越小,它就越容易成为一个单调非降的序列。

考虑反悔,即新建一个大根堆,每一次提出选择过的最大元素。

如果当前元素比大根堆顶更小,即不满足非降,就踢掉原来的堆顶,放上当前元素成为堆顶,更新答案。

答案更新加上两者差即可,同理于之前求 ab 求差的过程。

#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;
}
posted @   MistZero  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示