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("");
}
}