反悔贪心

用处

这个不知道怎么说。

如果能够抵消之前操作的贪心,都叫反悔贪心吧。

直接看例题。

题目

CF865D Buy Low Sell High

最经典的反悔贪。

如果买入了一个价值为 \(a_i\) 的股票,可以在价值为 \(a_j\) 的时候卖出,当然,可能在价值为 \(a_k\) 卖出的时候价值更高,那怎么办?

举个例子。

对于股票序列:1 2 100

先考虑维护一个集合,表示可以买入的股票价值。

最开始把价值为 \(1\) 的股票放进集合中,表示可以买这个股票。

当股票价值为 \(2\) 时,发现如果此时卖出,可以获得 \(1\) 的价值,那么卖出此股票,但是为了反悔,再在集合中加入价值为 \(2\) 的股票。

当股票价值为 \(100\) 时,集合中还有一个价值为 \(2\) 的股票,那么可以买入这个价值为 \(2\) 的股票,获得 \(98\) 的价值。

最终获得了 \(99\) 的价值,也就等于在价值为 \(1\) 时买入股票,在价值为 \(100\) 时卖出股票,对于在价值为 \(2\) 时卖出股票的操作被反悔掉了。

现在总结一下这道题的流程:

  1. 按顺序枚举股票。
  2. 对于当前价值为 \(a_i\) 的股票,如果要卖出它:
    • 考虑在集合中找到一个价值最小的股票,设为 \(x\)
    • 如果 \(a_i\gt x\),也就是卖出能够赚钱,那么就卖出价值 \(a_i\) 的股票,同时往集合中加入价值为 \(a_i\) 的股票,如果在后面选择这价值 \(a_i\) 的股票,就表示把卖出它的操作给反悔掉了。
  3. 如果不选择卖出价值为 \(a_i\) 的股票,那么把它加入集合。
代码
#include <bits/stdc++.h>
#define int long long

void Freopen() {
    freopen("", "r", stdin);
    freopen("", "w", stdout);
}

using namespace std;
const int N = 3e5 + 10, M = 2e5 + 10, inf = 1e9, mod = 998244353;

int n, ans;
int a[N];

priority_queue< int> q;

signed main() {
    ios :: sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    cin >> n;
    for ( int i = 1; i <= n; i ++) cin >> a[i];

    for ( int i = 1; i <= n; i ++) {
        if (q.size()) {
            int x = -q.top();
            if (a[i] > x) ans += a[i] - x, q.pop(), q.push(-a[i]);
        }
        // 这里表示要卖出 a_i
        
        q.push(-a[i]);
        // 这里表示不卖出 a_i
    }

    cout << ans << '\n';

    return 0;
}

[JSOI2007] 建筑抢修

首先先按照 \(T_2\) 从小到大排序。

然后遍历嘛,记录一个遍历 now 表示当前用的时间,同时维护一个集合,存修过的房子的 \(T_1\)

现在遍历到房子 \(i\),如果时间够修房子 \(i\),那么直接修了;如果不行,则在集合中选出最大的 \(T_1\),记对应的房子编号为 \(j\),如果 \({T_1}_j\gt {T_1}_i\),那么就进行反悔:反悔修房子 \(j\),而修房子 \(i\)

为什么这样做最优?因为无论如何都只能在房子 \(i\)\(j\) 中选一个修了,但是修房子 \(i\) 占用的时间更小,能够给后面的房子留下更多时间,所以选择房子 \(i\)

代码
#include <bits/stdc++.h>
#define int long long

void Freopen() {
    freopen("", "r", stdin);
    freopen("", "w", stdout);
}

using namespace std;
const int N = 2e5 + 10, M = 2e5 + 10, inf = 1e9, mod = 998244353;

int n;

struct node {
    int t1, t2;
} p[N];

priority_queue< int> q;

signed main() {
    ios :: sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    cin >> n;

    for ( int i = 1; i <= n; i ++) {
        cin >> p[i].t1 >> p[i].t2;
    }

    sort(p + 1, p + n + 1, [&]( node a, node b) {
        return a.t2 == b.t2 ? a.t1 < b.t1 : a.t2 < b.t2;
    });

    int ans = 0, now = 0;

    for ( int i = 1; i <= n; i ++) {
        if (now + p[i].t1 <= p[i].t2) now += p[i].t1, ans ++, q.push(p[i].t1);
        else {
            if (q.size()) {
                int x = q.top();
                if (x > p[i].t1) now = now - x + p[i].t1, q.pop(), q.push(p[i].t1);
            }
        }
    }

    cout << ans << '\n';

    return 0;
}
posted @ 2025-08-26 15:06  咚咚的锵  阅读(17)  评论(0)    收藏  举报