一本通1605股票交易


1605:股票交易

時間限制: 1000 ms         內存限制: 524288 KB

【題目描述】

原題來自:SCOI 2010

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

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

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

在第一天之前,lxhgww 手里有一大筆錢(可以認為錢的數目無限),但是沒有任何股票,當然,T 天以后,lxhgww 想要賺到最多的錢,聰明的程序員們,你們能幫助他嗎?

【輸入】

輸入數據第一行包括三個整數,分別是 T,MaxP,W。

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

【輸出】

輸出數據為一行,包括一個數字,表示 lxhgww 能賺到的最多的錢數。

【輸入樣例】

5 2 0
2 1 1 1
2 1 1 1
3 2 1 1
4 3 1 1
5 4 1 1

【輸出樣例】

3

【提示】

數據范圍與提示:

對於 30% 的數據,0W<T50,1MaxP50;
對於 50% 的數據,0W<T2000,1MaxP50;
對於 100% 的數據,0W<T2000,1MaxP2000,1BPiAPi1000,1ASi,BSiMaxP。

 

sol:一本通居然沒有數據范圍太優秀了

很容易發現可以dp,dp[i][j]表示到第i個位置,有j張股票最多賺多少錢

先考慮暴力dp

1):dp[i][j]由dp[i-1][j]直接轉移過來,dp[i][j]=max(dp[i][j],dp[i-1][j])

2):直接從0開始買股票 dp[i][j]=max(dp[i][j],j*AP)  (0<j≤MaxP)

3):買股票,股票從 k 張變為 j 張,dp[i][j]=max(dp[i][j],dp[i-W-1][k]-(j-k)*AP)

4):賣股票,股票從 k 張變成 j 張,dp[i][j]=max(dp[i][j],dp[i-W-1][k]+(k-j)*BP)

#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-');
        ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48);
        ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');
        return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
inline void writeln(ll x)
{
    write(x);
    putchar('\n');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) writeln(x)
const int N=2005;
int T,MaxP,W;
int dp[N][N];
int main()
{
//    freopen("trade1.in","r",stdin);
    int i,j,k;
    R(T); R(MaxP); R(W);
    memset(dp,-63,sizeof dp);
    for(i=1;i<=T;i++)
    {
        int AP=read(),BP=read(),AS=read(),BS=read();
        for(j=1;j<=min(AS,MaxP);j++) dp[i][j]=-1*AP*j;
        for(j=0;j<=MaxP;j++) dp[i][j]=max(dp[i][j],dp[i-1][j]);
        if(i<=W+1) continue;
        for(j=1;j<=MaxP;j++)
        {
            for(k=max(j-AS,0);k<j;k++)
            {
                dp[i][j]=max(dp[i][j],dp[i-W-1][k]-AP*(j-k));
                /*
                    dp[i][j]=max(dp[i][j],dp[i-W-1][k]-AP*j+AP*k);
                    dp[i][j]=max(dp[i][j],(dp[i-W-1][k]+AP*k)-AP*j)
                    (dp[i-W-1][k]+AP*k)最大的單調隊列隊首
                */
            }
        }
        for(j=0;j<MaxP;j++)
        {
            for(k=j+1;k<=min(MaxP,j+BS);k++)
            {
                dp[i][j]=max(dp[i][j],dp[i-W-1][k]+(BP*(k-j)));
                /*
                    dp[i][j]=max(dp[i][j],dp[i-W-1][k]+BP*k-BP*j);
                    dp[i][j]=max(dp[i][j],(dp[i-W-1][k]+BP*k)-BP*j);
                    (dp[i-W-1][k]+BP*k)最大的單調隊列隊首
                */
            }
        }
    }
    Wl(max(dp[T][0],0));
    return 0;
}
/*
input
5 2 0
2 1 1 1
2 1 1 1
3 2 1 1
4 3 1 1
5 4 1 1
output
3
*/
暴力代碼

然后因為這是暴力dp轉移,復雜度是T*MaxP*MaxP,可以得到70pts的好成績

單調隊列優化

把式子拆開可得如下(暴力代碼注釋)

dp[i][j]=max(dp[i][j],dp[i-W-1][k]-AP*j+AP*k);
dp[i][j]=max(dp[i][j],(dp[i-W-1][k]+AP*k)-AP*j)
所以可以維護一個單調隊列,(dp[i-W-1][k]+AP*k)最大的單調隊列隊首

另一個同理

#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-');
        ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48);
        ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');
        return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
inline void writeln(ll x)
{
    write(x);
    putchar('\n');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) writeln(x)
const int N=2005,inf=0x3f3f3f3f;
int T,MaxP,W;
int dp[N][N];
struct Record
{
    int Shuz,Weiz;
}Ddq[N];
int main()
{
//    freopen("trade1.in","r",stdin);
    int i,j,Head,Tail;
    R(T); R(MaxP); R(W);
    memset(dp,-63,sizeof dp);
    for(i=1;i<=T;i++)
    {
        int AP=read(),BP=read(),AS=read(),BS=read();
        for(j=1;j<=min(AS,MaxP);j++) dp[i][j]=-1*AP*j;
        for(j=0;j<=MaxP;j++) dp[i][j]=max(dp[i][j],dp[i-1][j]);
        if(i<=W+1) continue;
        Head=1; Tail=0;
        for(j=0;j<=MaxP;j++)
        {
            while(Head<Tail&&Ddq[Head].Weiz<j-AS) Head++;
            while(Head<=Tail&&dp[i-W-1][j]+AP*j>Ddq[Tail].Shuz) Tail--;
            Ddq[++Tail]=(Record){dp[i-W-1][j]+AP*j,j};
            dp[i][j]=max(dp[i][j],Ddq[Head].Shuz-j*AP);
        }
        Head=1; Tail=0;
        for(j=MaxP;j>=0;j--)
        {
            while(Head<Tail&&Ddq[Head].Weiz>j+BS) Head++;
            while(Head<=Tail&&dp[i-W-1][j]+BP*j>Ddq[Tail].Shuz) Tail--;
            Ddq[++Tail]=(Record){dp[i-W-1][j]+BP*j,j};
            dp[i][j]=max(dp[i][j],Ddq[Head].Shuz-j*BP);
        }
    }
    int ans=0;
    for(i=0;i<=MaxP;i++) ans=max(ans,dp[T][i]);
    Wl(ans);
    return 0;
}
/*
input
5 2 0
2 1 1 1
2 1 1 1
3 2 1 1
4 3 1 1
5 4 1 1
output
3
*/
單調隊列優化


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM