洛谷 P2569 [SCOI2010] 股票交易 題解

AIRSDREAM發表於2024-08-15

題目:

題目描述

最近 lxhgwwlxhgww 又迷上了投資股票,透過一段時間的觀察和學習,他總結出了股票行情的一些規律。

透過一段時間的觀察,lxhgwwlxhgww 預測到了未來 T 天內某隻股票的走勢,第 i 天的股票買入價為每股 ���APi,第 i 天的股票賣出價為每股 ���BPi(資料保證對於每個 i,都有 ���≥���APiBPi),但是每天不能無限制地交易,於是股票交易所規定第 i 天的一次買入至多隻能購買 ���ASi 股,一次賣出至多隻能賣出 ���BSi 股。

另外,股票交易所還制定了兩個規定。為了避免大家瘋狂交易,股票交易所規定在兩次交易(某一天的買入或者賣出均算是一次交易)之間,至少要間隔 W 天,也就是說如果在第 i 天發生了交易,那麼從第 �+1i+1 天到第 �+�i+W 天,均不能發生交易。同時,為了避免壟斷,股票交易所還規定在任何時間,一個人的手裡的股票數不能超過 MaxPMaxP。

在第 11 天之前,lxhgwwlxhgww 手裡有一大筆錢(可以認為錢的數目無限),但是沒有任何股票,當然,T 天以後,lxhgwwlxhgww 想要賺到最多的錢,聰明的程式設計師們,你們能幫助他嗎?

輸入格式

輸入資料第一行包括 33 個整數,分別是 T,MaxPMaxP,W。

接下來 T 行,第 i 行代表第 �−1i1 天的股票走勢,每行 44 個整數,分別表示 ���, ���, ���, ���APi, BPi, ASi, BSi

輸出格式

輸出資料為一行,包括 11 個數字,表示 lxhgwwlxhgww 能賺到的最多的錢數。

輸入輸出樣例

輸入 #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≤�<�≤50,1≤MaxP≤500W<T50,1MaxP50;
  • 對於 50%50% 的資料,0≤�<�≤2000,1≤MaxP≤500W<T2000,1MaxP50;
  • 對於 100%100% 的資料,0≤�<�≤2000,1≤MaxP≤20000W<T2000,1MaxP2000;
  • 對於所有的資料,1≤���≤���≤1000,1≤���,���≤MaxP1BPiAPi1000,1ASi,BSiMaxP

思路:

看到題目和資料範圍<=2000,一眼dp

考慮狀態定義,日期肯定為狀態之一,

接著在持有股票數量和賺的錢中選其一

考慮到錢數可能很大,所以使用股票數作為狀態

可得dp(i,j)->第i天時,持股數為j時最多賺的錢

狀態滿足無後效性

稍微思考,可得轉移方程

買入:dp(i,j)=max(dp(k,p)-(j-p)*ap[i] (k∈{x|0<=x<=i-w},p∈{x|j-as[i]<=x<=j}))

賣出:dp(i,j)=max(dp(k,p)+(p-j)*bp[i] (k∈{x|0<=x<=i-w},p∈{x|j<=x<=j+bs[i]}))

發現暴力會T飛

考慮最佳化

首先,由(k∈{x|0<=x<=i-w},p∈{x|j<=x<=j+bs[i]})可以觀察到我們維護的是一段連續區間裡的最大值

那麼考慮單調佇列

有一個重要結論:只有股票數相同時,錢數才是可以比較的

所以我們要開MaxP維的單調佇列,維護每個持股數時的最大賺錢

在過程中還要開兩個單調佇列,維護買入、賣出操作是的最優解

AC程式碼:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2100,inf=1e9;
int T,n,w;
int ap[N],bp[N],as[N],bs[N];
struct node{
int v,g,p;
};
deque <node>q[N];
deque <node>qa;
deque <node>qb;
int dp[N][N];
signed main(){
cin>>T>>n>>w;
for(int i=1;i<=T;i++){
cin>>ap[i]>>bp[i]>>as[i]>>bs[i];
}
int ans=0;
q[0].push_back({inf,0,0});
for(int i=1;i<=T;i++){
//for(int j=0;j<=n;j++) while(!q[j].empty() and q[j].front().p<i-w) q[j].pop_front();
qa.clear();qb.clear();
//mr
for(int j=0;j<=n;j++){
while(!qa.empty() and qa.front().g<j-as[i]) qa.pop_front();
if(!q[j].empty()){
node in=q[j].front();
while(!qa.empty() and qa.back().v-(j-qa.back().g)*ap[i]<=in.v) qa.pop_back();
qa.push_back(in);
}
if(!qa.empty()){
node a=qa.front();
dp[i][j]=max(a.v-(j-a.g)*ap[i],dp[i][j]);
}
}
//mc
for(int j=n;j>=0;j--){
while(!qb.empty() and qb.front().g>j+bs[i]) qb.pop_front();
if(!q[j].empty()){
node in=q[j].front();
while(!qb.empty() and qb.back().v+(qb.back().g-j)*bp[i]<=in.v) qb.pop_back();
qb.push_back(in);
}
if(!qb.empty()){
node b=qb.front();
dp[i][j]=max(b.v+(b.g-j)*bp[i],dp[i][j]);
}
}
if(i-w>=0){
for(int j=0;j<=n;j++){
while(!q[j].empty() and q[j].back().v<=dp[i-w][j]) q[j].pop_back();
q[j].push_back({dp[i-w][j],j,i});
ans=max(ans,dp[i][j]);
}
}
}
cout<<ans-inf<<endl;

return 0;
}

相關文章