洛谷 CF865D Buy Low Sell High(反悔贪心)
传送门
解题思路
错误思路:对于每天的股票,若比当前入手的最低价股票高,则入手前面的,并在今天卖出去,再把今天的买入,为以后做准备。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int maxn=300005; int a[maxn],n; long long ans; priority_queue<int,vector<int>,greater<int> > q; int main(){ cin>>n; for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++){ if(!q.empty()&&q.top()<a[i]){ ans+=a[i]-q.top(); q.pop(); } q.push(a[i]); } cout<<ans; return 0; }
为什么错误了呢?
我们看这一组样例:
4
1 2 4 5
我们会在第一天买入,入队1,然后第二天卖出,出队1入队2,赚1差价,然后第三天买入第二天的,再卖出,出队2入队4,赚2,然后在第四天买入第三天的再卖出,入队4出队3,赚1.
一共赚了1+2+1=4。
但是很显然可以第一天买入第三天卖出,赚3,第二天买入第四天卖出,赚3,一共赚3+3=6。
Q:差在哪里呢?
A:第二天的邮票再做中间量后其实是可以再购买的。
所以
- 做法一:就是加一个vis的数组,表示买没买此邮票。优先队列中的变量可以改成pair。
- 做法二:然后翻了翻题解,发现不需要vis也可,只需要对于中间量在优先队列里加入两遍。(第一遍相当于可换,第二遍相当于可买),对于非中间量加入一遍(相当于可买)。
AC代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 const int maxn=300005; 7 int a[maxn],n; 8 bool vis[maxn]; 9 long long ans; 10 priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q; 11 int main(){ 12 cin>>n; 13 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 14 for(int i=1;i<=n;i++){ 15 if(!q.empty()&&q.top().first<a[i]){ 16 vis[q.top().second]=!vis[q.top().second]; 17 ans+=a[i]-q.top().first; 18 if(vis[q.top().second]) q.push(q.top()); 19 q.pop(); 20 q.push(make_pair(a[i],i)); 21 }else{ 22 q.push(make_pair(a[i],i)); 23 vis[i]=1; 24 } 25 } 26 cout<<ans; 27 return 0; 28 }