CF865D Buy Low Sell High
阿新 • • 發佈:2020-12-04
題目解析
首先,有一個錯誤的貪心策略:我們在能夠賺錢的時候就賣出股票。
基於這個思路,我們有一個錯誤的做法:對於某一天,我們查詢前面沒有用過的價格最小的一天,如果那一天的價格比現在小,就進行一次買入-賣出操作。這個可以用小根堆維護,每次都把股票價格壓入,然後每次找,如果要操作,就彈出。
當然,這個是錯誤的,我們可以把股票留在後面某一次賣出,可能會產生更優的答案。考慮反悔。如果一次交易的賣出價格為\(P_{sell}\),買入價格為\(P_{buy}\),那麼利潤其實可以表示為\(profit=(P_{sell}-P_i)+(P_i-P_{buy})\) \(P_i\)是任意一天的價格,就相當於我們在第\(i\)
注意,執行反悔操作之後,相當於我們第\(i\)天什麼都沒有做,那麼\(i\)還是可以作為買入的那一天的,所以還是要壓入。
還有一個點,是我想了很久的。就是如果我們壓入兩次,那麼在這一天我真的賣了,沒有反悔,而後面我們又把它彈出來作為買入,那麼在這一天我們既買入又賣出了,與題意不符。
注意到事實上不會發生這種情況,因為這樣操作等價於在最前面買入,最後面賣出。
►Code View
#include<cstdio> #include<algorithm> #include<queue> #include<cstring> using namespace std; #define N 100005 #define LL long long int rd() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48); c=getchar();} return f*x; } int n; LL ans; priority_queue<int,vector<int>,greater<int> >Q; int main() { n=rd(); for(int i=1;i<=n;i++) { int p=rd(); if(!Q.empty()) { int x=Q.top(); if(x<p) { Q.pop(); ans+=p-x; Q.push(p); } } Q.push(p); } printf("%lld\n",ans); return 0; } /* */