题意
t组输入,每组n个城市,给出每个城市的货物的价格,在每个城市可以进行三个操作:购买货物,卖出货物,不做操作,问从城市1到城市n(不能返回)最多能获得多少利润,且操作数最少(买和卖分别算一次操作)。
思路
首先,对于 1 2 10,我们可以这样考虑:在1号城市买入,在2号城市卖出,利润为2-1 = 1,但是我们发现3号城市利润更高,所以在2号城市的时候我们假装买入一份价格为2的货物,然后在3号卖出,重述一次整个过程:城市1买入(-1),城市2卖出(-1+2),城市二买入(-1+2-2),城市三卖出(-1+2-2+10 = 9),其实就相当于在1号买入,3号卖出,2号城市当作跳板,同样,操作数就算2次,那么我们可以把货物分成两类——直接购买的货物,当作跳板虚假买入的货物,那么直接购买的货物卖出后操作数就是2,跳板货物对操作数没有影响,所以操作数为0。如此,我们可以想到用一个优先队列维护一个结构体,结构体里存货物价格和类型(对操作数的影响,0或2),按照先价格从小到大,再类型从小到大的顺序出队。遍历一次所有城市,如果当前城市的价格大于队内最小的价值,说明卖出有利润,卖出并pop掉,再压入当前城市价格的两种类型的货物(具体看代码),最后输出即为答案。
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#define LL long long
using namespace std;
const int maxn = 1e5 + 10;
const double PI = acos(-1.0);
struct node {
int val, type;
bool operator<(const node b) const {//重载符号,达到先按照价格后按照类型从小到大排列
if (val != b.val) return val > b.val;
return type > b.type;
}
};
priority_queue<node> q;
int main(int argc, char const *argv[]) {
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
while (!q.empty()) q.pop();
int n;
cin >> n;
LL ans = 0, cnt = 0;
while (n--) {
int x;
cin >> x;
node p;
p.val = x;
p.type = 2;
if (!q.empty() && q.top().val < x) {//如果队内最小价格小于当前城市的价格,说明有利可图,卖出
ans += x - q.top().val;
cnt += q.top().type;
q.pop();
q.push(p);//压入两种类型的货物
p.type = 0;//当前货物可能是当作跳板卖出的,所以也要压入跳板
q.push(p);
} else
q.push(p);//当前城市不卖出货物,只有可能买入,故压入类型为操作数为2的货物
}
cout << ans << ' ' << cnt << endl;
}
return 0;
}