Loading

HDU-6438 Buy and Resell 思维 贪心

HDU-6438 Buy and Resell 思维 贪心

题意

\(n\)座城市,每座城市可以进行交易

1.花\(a_i\) 买入一个cube

2.花\(a_i\)卖出一个已经有的cube

3.不交易

假设你初始有无数钱,问最终的最大收益是多少,在最大收益情况下的最小交易次数是多少

\[T \leq 250 \\ 1\leq n \leq 10^5 \quad 1\leq a_i \leq 10^9 \]

分析

妥妥的思维题,开始还在想\(dp\) 什么的。

我们肯定贪心的希望用最小的买入来兑换最大的卖出。

但是直接这样想法是比较难做的。

注意到一个性质,若在\(i\) 处买入,\(j\) 处卖出,收益是\(a_j - a_i\) ,若后面有一个\(k\) 使得\(a_k - a_i > a_j - a_i\) ,那不妨在\(k\) 处卖出。注意到\(a_k - a_i = (a_k - a_j )+(a_j - a_i)\) ,有这样的传递性,这意味着我们可以假设就是在\(j\) 处卖出,又在\(j\)处买入了,这样操作是不影响答案的。

所以这里的\(j\) 有两重功能,一重就是作为中间量,维持收益最大。另一重就是本身作为买入。

实现这样的功能体现在代码上就是push两次(妙啊

细节:注意\(cnt\)

代码

map<int, int> vis;
struct S {
    ll w;
    S(){}
    S(ll _w):w(_w){}
    friend bool operator < (const S& a, const S& b) {
        return a.w > b.w;
    }
};
priority_queue<S> q;

int main() {
    int T = readint();
    while (T--) {
        while (!q.empty()) q.pop();
        vis.clear();
        ll res = 0;
        int cnt = 0;
        int n = readint();
        for (int i = 0; i < n; i++) {
            ll tmp = readll();
            if (!q.empty() && q.top().w < tmp) {
                ll val = q.top().w;
                q.pop();
                q.push(tmp);
                res += tmp - val;
                cnt++;
                if (vis[val])
                    cnt--, vis[val]--;
                vis[tmp]++;
            }
            q.push(S(tmp));
        }
        Put(res);
        printf(" %d", cnt << 1);
        puts("");
    }
}
posted @ 2020-09-05 21:12  MQFLLY  阅读(151)  评论(0编辑  收藏  举报