洛谷P2569 股票交易【dp】【單調隊列】
題目描述
最近 \text{lxhgww}lxhgww 又迷上了投資股票,通過一段時間的觀察和學習,他總結出了股票行情的一些規律。
通過一段時間的觀察,\text{lxhgww}lxhgww 預測到了未來 TT 天內某只股票的走勢,第 ii 天的股票買入價為每股 AP_iAPi?,第 ii 天的股票賣出價為每股 BP_iBPi?(數據保證對於每個 ii,都有 AP_i \geq BP_iAPi?≥BPi?),但是每天不能無限制地交易,於是股票交易所規定第 ii 天的一次買入至多只能購買 AS_iASi? 股,一次賣出至多只能賣出 BS_iBSi? 股。
另外,股票交易所還制定了兩個規定。為了避免大家瘋狂交易,股票交易所規定在兩次交易(某一天的買入或者賣出均算是一次交易)之間,至少要間隔 WW 天,也就是說如果在第 ii 天發生了交易,那麽從第 i+1i+1 天到第 i+Wi+W 天,均不能發生交易。同時,為了避免壟斷,股票交易所還規定在任何時間,一個人的手裏的股票數不能超過 \text{MaxP}MaxP。
在第 11 天之前,\text{lxhgww}lxhgww 手裏有一大筆錢(可以認為錢的數目無限),但是沒有任何股票,當然,TT 天以後,\text{lxhgww}lxhgww 想要賺到最多的錢,聰明的程序員們,你們能幫助他嗎?
輸入輸出格式
輸入格式:
輸入數據第一行包括 33 個整數,分別是 TT,\text{MaxP}MaxP,WW。
接下來 TT 行,第 ii 行代表第 i-1i?1 天的股票走勢,每行 44 個整數,分別表示 AP_i,\ BP_i,\ AS_i,\ BS_iAPi?, BPi?, ASi?, BSi?。
輸出格式:
輸出數據為一行,包括 11 個數字,表示 \text{lxhgww}lxhgww 能賺到的最多的錢數。
輸入輸出樣例
輸入樣例#1: 復制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\%30% 的數據,0\leq W<T\leq 50,1\leq\text{MaxP}\leq500≤W<T≤50,1≤MaxP≤50
對於 50\%50% 的數據,0\leq W<T\leq 2000,1\leq\text{MaxP}\leq500≤W<T≤2000,1≤MaxP≤50
對於 100\%100% 的數據,0\leq W<T\leq 2000,1\leq\text{MaxP}\leq20000≤W<T≤2000,1≤MaxP≤2000
對於所有的數據,1\leq BP_i\leq AP_i\leq 1000,1\leq AS_i,BS_i\leq\text{MaxP}1≤BPi?≤APi?≤1000,1≤ASi?,BSi?≤MaxP
題意:
一共t天,最多可以持有maxp支股票。給定每天股票買入賣出價格和每天的交易限額。問可以最多賺多少錢。
思路:
應該能夠想得到這是一個dp。子結構就是前i天能賺取的最多價格,這就是“階段”,也就是第一維。同時我們還需要記錄一下持有的股票數,因為狀態轉移時,不同的股票數的轉移是不同的。
因此,dp[i][j]表示第i天持有j的時候所能賺取的最大值。
對於每一天我們都有三種情況。
1.不買也不賣。 那麽轉移方程就是
2.買入。買入有分兩種情況,一種是之前什麽都沒有,這j股都是在第i天買的。
另一種是之前的某一天買了k股,今天買了j-k股。而且題目要求兩個交易的日子要間隔w天。
3.賣出。之前的某一天有k股,賣掉了k-j股,第i天剩下j股。
但是我們會發現狀態轉移的時候如果枚舉k,會出現O(n^3)的復雜度,需要進一步優化。
觀察狀態轉移方程我們可以把k合並同類項,比如賣出的式子可以變成
由於max{}中的是一個正數,假設我們設在j時這個值為x,擴展到j+1時,我們只有可能取x或者k=j時的值。他是一個遞增的選擇。
就可以用單調隊列來維護這個值了。
由於賣出是由比j大的k推出的,所以在轉移賣出這種情況的時候,j應該是逆序的。
1 #include <iostream> 2 #include <set> 3 #include <cmath> 4 #include <stdio.h> 5 #include <cstring> 6 #include <algorithm> 7 #include <vector> 8 #include <queue> 9 #include <map> 10 #include <bits/stdc++.h> 11 using namespace std; 12 typedef long long LL; 13 #define inf 0x7f7f7f7f 14 15 const int maxn = 2005; 16 int t, maxp, w; 17 struct node{ 18 int ap, bp, as, bs; 19 }day[maxn]; 20 int dp[maxn][maxn], que[maxn]; 21 22 int main() 23 { 24 scanf("%d%d%d", &t, &maxp, &w); 25 memset(dp, -inf, sizeof(dp)); 26 for(int i = 1; i <= t; i++){ 27 scanf("%d%d%d%d", &day[i].ap, &day[i].bp, &day[i].as, &day[i].bs); 28 } 29 for(int i = 1; i <= t; i++){ 30 for(int j = 0; j <= day[i].as; j++){ 31 dp[i][j] = -j * day[i].ap; 32 } 33 for(int j = 0; j <= maxp; j++){ 34 dp[i][j] = max(dp[i][j], dp[i - 1][j]); 35 } 36 if(i <= w)continue; 37 int head = 1, tail = 0; 38 for(int j = 0; j <= maxp; j++){ 39 while(dp[i - w - 1][que[tail]] + que[tail] * day[i].ap <= dp[i - 1 - w][j] + j * day[i].ap && head <= tail){ 40 tail--; 41 } 42 que[++tail] = j; 43 while(j - que[head] > day[i].as){ 44 head++; 45 } 46 dp[i][j] = max(dp[i][j], dp[i - w - 1][que[head]] - (j - que[head]) * day[i].ap); 47 } 48 49 head = 1, tail = 0; 50 for(int j = maxp; j >= 0; j--){ 51 while(dp[i - w - 1][que[tail]] + que[tail] * day[i].bp <= dp[i - 1 - w][j] + j * day[i].bp && head <= tail){ 52 tail--; 53 } 54 que[++tail] = j; 55 while(que[head] - j > day[i].bs){ 56 head++; 57 } 58 dp[i][j] = max(dp[i][j], dp[i - 1 - w][que[head]] + (que[head] - j) * day[i].bp); 59 } 60 } 61 62 63 int ans = -1; 64 for(int j = 0; j <= maxp; j++){ 65 ans = max(ans, dp[t][j]); 66 } 67 printf("%d\n", ans); 68 return 0; 69 }
洛谷P2569 股票交易【dp】【單調隊列】