反悔贪心

用处

这个不知道怎么说。

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

直接看例题。

题目

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  咚咚的锵  阅读(53)  评论(0)    收藏  举报