洛谷題目鏈接:[SCOI2010]股票交易
題目描述
最近lxhgww又迷上了投資股票,經過一段時間的觀察和學習,他總結出了股票行情的一些規律。c++
經過一段時間的觀察,lxhgww預測到了將來T天內某隻股票的走勢,第i天的股票買入價爲每股APi,第i天的股票賣出價爲每股BPi(數據保證對於每一個i,都有APi>=BPi),可是天天不能無限制地交易,因而股票交易所規定第i天的一次買入至多隻能購買ASi股,一次賣出至多隻能賣出BSi股。程序員
另外,股票交易所還制定了兩個規定。爲了不你們瘋狂交易,股票交易所規定在兩次交易(某一天的買入或者賣出均算是一次交易)之間,至少要間隔W天,也就是說若是在第i天發生了交易,那麼從第i+1天到第i+W天,均不能發生交易。同時,爲了不壟斷,股票交易所還規定在任什麼時候間,一我的的手裏的股票數不能超過MaxP。學習
在第1天以前,lxhgww手裏有一大筆錢(能夠認爲錢的數目無限),可是沒有任何股票,固然,T天之後,lxhgww想要賺到最多的錢,聰明的程序員們,大家能幫助他嗎?優化
輸入輸出格式
輸入格式:url
輸入數據第一行包括3個整數,分別是T,MaxP,W。spa
接下來T行,第i行表明第i-1天的股票走勢,每行4個整數,分別表示APi,BPi,ASi,BSi。.net
輸出格式:code
輸出數據爲一行,包括1個數字,表示lxhgww能賺到的最多的錢數。隊列
輸入輸出樣例
輸入樣例#1:ci
5 2 0 2 1 1 1 2 1 1 1 3 2 1 1 4 3 1 1 5 4 1 1
輸出樣例#1:
3
說明
對於30%的數據,0<=W<T<=50,1<=MaxP<=50
對於50%的數據,0<=W<T<=2000,1<=MaxP<=50
對於100%的數據,0<=W<T<=2000,1<=MaxP<=2000
對於全部的數據,1<=BPi<=APi<=1000,1<=ASi,BSi<=MaxP </br>
一句話題意: 天天最多能夠買進$as_i$張股票,賣出$bs_i$張股票,可是每一個時刻手中的票最多都只能有$maxp$張,每買入一張股票能夠得到$ap_i$元,賣出一張股票能夠得到$bp_i$元,且若是第$i$天進行了交易,那麼從第$i+1$到第$i+w$天都不能再進行交易,問到第$n$天最多能夠得到的價值. </br>
題解: 這個數據範圍顯然是能DP的.咱們先想一下狀態該如何定義.
首先根據這個狀態轉移的條件,有交易的天數限制,因此顯然是須要一維來存交易到第幾天的.而後是對於手中持有的股票數量的限制,顯然至少是須要一重循環來枚舉目前手中持有的股票數量的,因此考慮將這個也加入狀態中.可得狀態$f[i][j]$表示到第$i$天手中持有$j$張股票的最大利益.那麼最後的答案就是 $f[n][0]$,由於顯然在最後一天把全部股票都賣出不會比留着股票差.
而後想一下如何轉移這個狀態.那麼從上一個狀態到如今的狀態$f[i][j]$,顯然只有這幾種狀況:
- 第$i-1$天沒有買/賣股票,第$i$天的最大收益爲$f[i-1][j]$.
- 第$i-w-1$天進行了股票的買賣且擁有$k(k<j)$張股票,第$i$天有股票$j$張,此時買入了$j-k$張股票,可得最大收益爲$f[i][j] = max(f[i][j], f[i-w-1][k]-(j-k)*ap[i])$
- 第$i-w-1$天進行了股票的買賣且擁有$k(k>j)$張股票,第$i$天有股票$j$張,此時賣出了$k-j$張股票,可得最大收益爲$f[i][j]=max(f[i][j], f[i-w-1][k]+(k-j)*bp[i])$
此外沒有別的轉移方式了,因此能夠列出狀態轉移方程.
那麼考慮了狀態轉移以後,仔細想一想發現這個時間複雜度是$O(T*maxp^2)$的,顯然這樣是不能過100%的數據的.因此須要使用一些優化.
這裏咱們將這個狀態轉移方程展開一下,發現: $$f[i-w-1][k]+(k-j)×bp[i]=(f[i-w-1][k]+k×bp[i])-j×bp[i]$$ 也就是說,在枚舉了$i,j$的狀況下,$i,j$是能夠看作常數的,那麼此時對答案有影響的就只有$k$了 .而且咱們發現, 若是$j$是以正確的順序枚舉的,那麼$k$也就是逐漸在平移的了.好比說買入股票,那麼擁有的股票也就會愈來愈多,賣出的話擁有的股票就會愈來愈少,事實上這個是符合 單調隊列優化的條件的,因此咱們能夠考慮將目前擁有的股票數存入單調隊列中,優化後複雜度爲$O(T*maxp)$.
固然分開和賣出的兩種狀況是要分開使用隊列的,由於他們各自具備單調性,可是合起來並無.
#include<bits/stdc++.h> using namespace std; const int N=2000+5; int n, maxp, w, ap[N], bp[N], as[N], bs[N], ans = 0; int f[N][N], h1, h2, t1, t2, q1[N], q2[N]; int main(){ cin >> n >> maxp >> w; for(int i=1;i<=n;i++) cin >> ap[i] >> bp[i] >> as[i] >> bs[i]; memset(f, 128, sizeof(f)); f[0][0] = 0; for(int i=1;i<=n;i++){ for(int j=0;j<=maxp;j++) f[i][j] = max(f[i][j], f[i-1][j]); for(int j=0;j<=as[i];j++) f[i][j] = max(f[i][j], -1*j*ap[i]); if(i <= w) continue; h1 = h2 = 1, t1 = t2 = 0; for(int j=0;j<=maxp;j++){ while(h1 <= t1 && f[i-w-1][q1[t1]]-ap[i]*(j-q1[t1]) <= f[i-w-1][j]) t1--; while(h1 <= t1 && j-q1[h1] > as[i]) h1++; q1[++t1] = j; if(h1 <= t1) f[i][j] = max(f[i][j], f[i-w-1][q1[h1]]-(j-q1[h1])*ap[i]); } h1 = h2 = 1, t1 = t2 = 0; for(int j=maxp;j>=0;j--){ while(h2 <= t2 && f[i-w-1][q2[t2]]+bp[i]*(q2[t2]-j) <= f[i-w-1][j]) t2--; while(h2 <= t2 && q2[h2]-j > bs[i]) h2++; q2[++t2] = j; if(h2 <= t2) f[i][j] = max(f[i][j], f[i-w-1][q2[h2]]+(q2[h2]-j)*bp[i]); } } printf("%d\n", f[n][0]); return 0; }