HDU 6438 Buy and Resell(存在决策包容性的可悔贪心)

题目链接

题目大意

  给你n个商品,对于每个商品可以选择三个操作之一: 1.以这个商品价格买入这个商品 2.如果之前买过某商品以这个商品价格卖出一个商品 3.什么也不做

解题思路

  先讲一个别的问题。对于A, B, C, D四个数,任你选出几对数求最大差值, 如果(A<B<C, B>D),是有两种选择方法的,一种是C-A,一种是D-A, C-B,显然是前者更优,因为B>D,所以第二种比第一种少了B-D。这也就证明了一个结论:对于当前这个数来说,一定是选前面最小的数更优。
  回到本题,我们从左到右扫过每一个数,对于第一次决策,如果前面存在一个最小的数比当前的数小,答案就加上他们的差值,如果后面有一个更大的数呢?有两种选择,可以再选一个前面最小的没有在决策里的数加上他们的差值,也可以替换掉前一个方案,你可能会问,如果我替换掉前面的方案,被替换方案中的数不是没法再跟他前面的数相减了吗?如果之前的决策能被替换,可以参考上面的情况,其肯定是满足(B geq D)的,其中D是我们前面的最小值,B是决策中要被替换的数,这样的话就转换成了上面的问题了。
  具体做法是,我们用一个multiset S来维护前面可选的最小的数,用一个优先队列q来维护决策中能被替换的最小的数,然后从左到右扫一遍序列,如果S和q为空,说明没有方案可选,将其加进S中。如果S不为空,q为空,说明没有替换方案,就从S中选一个最小的数a[j],然后把决策a[i], a[j]加入q中并计算贡献(q以a[i]为第一关键字从小到大排序)。如果S不为空,q不为空,则贪心的选择替换或者进行新的决策,如果替换方案的话,原先的a[i]是可以再利用的,再将其加入S中。如果S为空,q不为空,那就只能考虑是否替换更优的决策了。

代码

const int maxn = 2e5+10;
const int maxm = 1e7+10;
int a[maxn];
int main() {
    int __; scanf("%d", &__);
    while(__--) {
        int n; scanf("%d", &n);
        priority_queue<P, vector<P>, greater<P> > pq;
        multiset<int> st;
        ll sum = 0, cnt = 0;
        for (int i = 1; i<=n; ++i) {
            scanf("%d", &a[i]);
            if (st.empty() && pq.empty()) st.insert(a[i]);
            else if (!st.empty()) {
                if (!pq.empty() && a[i]-pq.top().x>0 && a[i]-pq.top().x>=a[i]-*st.begin()) {
                    P t = pq.top(); pq.pop();
                    sum += a[i]-t.x;
                    pq.push({a[i], t.y});
                    st.insert(t.x);
                }
                else if (*st.begin()<a[i]) {
                    sum += a[i]-*st.begin();
                    cnt += 2;
                    pq.push({a[i], *st.begin()});
                    st.erase(st.begin());
                }
                else st.insert(a[i]);
            }
            else if (!pq.empty()) {
                if (a[i]>pq.top().x) {
                    P t = pq.top(); pq.pop();
                    sum += a[i]-t.x;
                    pq.push({a[i], t.y});
                    st.insert(t.x);
                }
                else st.insert(a[i]);
            }
        }
        cout << sum << ' ' << cnt << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/shuitiangong/p/15191436.html