已知接下來N天的股票價格,天天你能夠買進一股股票,賣出一股股票,或者什麼也不作.N天以後你擁有的股票應爲0,固然,但願這N天內可以賺足夠多的錢.
輸入:
第一行一個整數天數N(2<=N<=300000).
第二行N個數字p1,p2...pN(1<=pi<=10^6),表示天天的價格.
輸出: N天結束後能得到的最大利潤.c++
很是經典的貪心問題spa
用一個優先隊列小根堆。翻譯
假設每一個股票都買入。code
當前的股票價格>堆頂的時候,把這個股票加進去兩次。而後彈出堆頂。blog
不然加進去一次。隊列
把這個差價計入ans,ans+=price[i]-q.top()it
什麼意義呢?io
首先,咱們雖然假設都買入,可是並不必定都買。class
咱們只有在計算差價的時候,至關於纔會把某個價格買入,再以price[i]賣出。queue
而咱們把這個股票加進去兩次,
一次是正常的假設買入。爲了以後可能賺取差價。
另外一次是爲了反悔。
假設股票價格是:3 7 10
最優解是3買入,10賣出,賺7元
也就是說,我以3價格買入,但我會在7元的時候賣出。
可是7元賣可能不是最優秀的。
因此,咱們把7元再加進去,當輪到10元的時候,這個7元會再當作一個股票賣出ans+=10-7
發現,有意思的是,10-3=(10-7)+(7-3)
這就至關於3元買入,10元賣出。7元這天摸魚。
若是10後面假設還有一個20
即3,7,10,20
那麼,咱們10元以後,隊列裏有7,10,10
20元會7元買入,20元賣出。至關於7元這天買入了一股。
這樣下去,咱們總能把最少的價格買入,儘可能多的價格賣出。
若是不是最優秀的話,就不買不賣了。就是最後優先隊列裏剩下的一些。就是預約買入,可是實際沒有買入的部分。
#include<bits/stdc++.h> using namespace std; const int N=300000+10; int n; int p[N]; priority_queue<int,vector<int>,greater<int> >q; long long ans; int main() { scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&p[i]); q.push(p[i]); if(!q.empty()&&q.top()<p[i]){ ans+=p[i]-q.top(); q.pop(); q.push(p[i]); } }printf("%lld",ans);return 0; }
總結:
反悔堆的比較厲害的應用了。
利用差價的關係,直接處理。
怎麼想到的?
首先要想到貪心,而後這個題確定要用一個反悔堆之類。
那麼,咱們假設先買入,仍是先都不買?
都不買太被動。
那就都買入,而後結算的時候,再真實買入。
可是對於不是最優的拋售天怎麼辦?
利用差價。便可。