1. 程式人生 > >洛谷P2569 股票交易【dp】【單調隊列】

洛谷P2569 股票交易【dp】【單調隊列】

還需 可能 之間 pri 數字 間隔 col node .com

題目描述

最近 \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}\leq500W<T50,1MaxP50

對於 50\%50% 的數據,0\leq W<T\leq 2000,1\leq\text{MaxP}\leq500W<T2000,1MaxP50

對於 100\%100% 的數據,0\leq W<T\leq 2000,1\leq\text{MaxP}\leq20000W<T2000,1MaxP2000

對於所有的數據,1\leq BP_i\leq AP_i\leq 1000,1\leq AS_i,BS_i\leq\text{MaxP}1BPi?APi?1000,1ASi?,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】【單調隊列】