链接
https://acm.hdu.edu.cn/showproblem.php?pid=6438
题意
有 $n$ 天,每天有一个价格,每天可以执行一次操作,买入或卖出,求最大收益且保证操作次数最少。
思路
有一个贪心策略是:在价格低的时候买入,在可以赚钱的时候卖出。
显然该策略是错误的,可以在之后能赚更多的某天卖出。
设 $a_i<a_j<a_k$ $(i<j<k)$,有 $a_k-a_i=(a_j-a_i)+(a_k-a_j)$。
可以发现按照错误的贪心策略,在第 $j$ 天卖出,我们可以在更优的第 $k$ 天加上差值来更新全局最优解,而第 $j$ 天相当于中间值被消掉了,我们可以用优先队列来维护最小值,这就是反悔贪心。
因为要让操作次数最少,所以我们要找的是最小且已经被卖出过的更新最优解,没有被卖出过的,则只能增加操作次数。
因为我们有买入必有卖出,所以我们在卖出时统计次数,因此可以强行买入所有,即每次都会入队一次,若可以更新最优解,再入队一次,上述做法显然不存在某一天既买入又卖出。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| #include <bits/stdc++.h> #define SZ(x) (int)(x).size() #define ALL(x) (x).begin(),(x).end() #define PB push_back #define EB emplace_back #define MP make_pair #define FI first #define SE second using namespace std; typedef double DB; typedef long double LD; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII; typedef vector<int> VI; typedef vector<PII> VPII;
struct R { int x,y; R() {} R(int x,int y):x(x),y(y) {} bool operator < (const R &T) const { return x>T.x||x==T.x&&y>T.y; } }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T;cin>>T; while(T--) { int n;cin>>n; priority_queue<R> q; VI a(n+1); for(int i=1;i<=n;i++) { cin>>a[i]; if(SZ(q)&&q.top().x<a[i]) { auto u=q.top(); q.pop(); q.emplace(a[i],u.y==0x3f3f3f3f?u.x:u.y); } q.emplace(a[i],0x3f3f3f3f); } pair<LL,int> res=MP(0,0); while(SZ(q)) { auto u=q.top(); q.pop(); if(u.x>u.y) res.FI+=u.x-u.y,res.SE+=2; } cout<<res.FI<<' '<<res.SE<<'\n'; } return 0; }
|