zoukankan      html  css  js  c++  java
  • 股票交易 (单调队列优化DP)

    股票交易



    $ solution: $

    这道题以前就写了,题目很好,但自己没有发题解,来补一篇:

    首先,题目出得很有迷惑性,但我们不难想到状态要设天数,和自己手上的股票数目(因为这两个就是充要信息)。而我们转移也比较常规,跟着题意模拟就行:

    1. (不买不卖): $ f[i][j]=f[i-1][j] $
    2. (买入): $ f[i][j]=max{~sum_{p=1}^{p<i} sum_{q=0}^{q<j} f[p][q]-(j-q) imes AP[i]~} $
    3. (卖出): $ f[i][j]=max{~sum_{p=1}^{p<i} sum_{q=0}^{q>j} f[p][q]+(q-j) imes BP[i]~} $

    但是我们发现这样转移是 $ n^4 $ 的。因为我们每一个 $ f[i][j] $ 需要往前枚举 $ p $ ,然后因为股票可以买入卖出,还要枚举一个 $ q $ 。就是每一个 $ f[i][j] $ 都要完全枚举所有的 $ f[p][q] $ 来转移。但是我们可以发现我们的 $ p $ 是完全可以不用枚举,因为第一个转移保证了 $ f[i-1] $ 就是最优的。于是转移变成了 $ n^3 $ 但是数据范围告诉我们这样还不够。

    1. (买入): $ f[i][j]=max{~sum_{k=1}^{k<j} f[i-1][k]-(j-k) imes AP[i]~} $
    2. (卖出): $ f[i][j]=max{~sum_{k=1}^{k>j} f[i-1][k]+(k-j) imes BP[i]~} $

    这两个式子其实把括号拆开后就是一个式子:

    $ f[i][j]=max{~sum_{k=1}^{k>j} f[i-1][k]+k imes P[i]-j imes P[i]~} $

    单调队列优化: 我们发现我们买入卖出的式子是一个变量单调递增的,我们的 $ i $ 是最外层循环,在内层循环里它相当于定值,而我们的k和j在式子中是独立的,完全可以用单调队列维护 $ f[i-1][k]+k imes P[i] $ ,而 $ -j imes P[i] $ 就是定值,只需要来两次单调队列分别对应 $ AP[i] $ 和 $ BP[i] $ 即可。



    $ code: $

    #include<iostream>
    #include<cstdio>
    #include<iomanip>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<ctime>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    
    #define ll long long
    #define db double
    #define inf 0x7fffffff
    #define rg register int
    #define max(A,B) (A>B?A:B)
    
    using namespace std;
    
    int n,m,w,l,r,now,a,b,c,d,ans;
    int f[2001][2001],t[2001],p[2001];
    
    inline int qr(){
        char ch;
        while((ch=getchar())<'0'||ch>'9');
        int res=ch^48;
        while((ch=getchar())>='0'&&ch<='9')
            res=res*10+(ch^48);
        return res;
    }
    
    int main(){
        //freopen("1.in","r",stdin);
        //freopen(".out","w",stdout);
        n=qr(),m=qr(),w=qr();
        for(rg i=0;i<=n;++i)
            for(rg j=0;j<=m;++j)
                f[i][j]=-inf;
        for(rg i=1;i<=n;++i){
            a=qr(),b=qr();
            c=qr(),d=qr();
            for(rg j=0;j<=c;++j)
                f[i][j]=-1*j*a;
            for(rg j=0;j<=m;++j)
                f[i][j]=max(f[i][j],f[i-1][j]);
            if(i<=w)continue;
            l=1;r=0;
            for(rg j=0;j<=m;++j){
                now=f[i-w-1][j]+j*a;
                while(l<=r&&p[l]<j-c)++l;
                while(l<=r&&t[r]<=now)--r;
                t[++r]=now;p[r]=j;
                if(l <= r)f[i][j]=max(f[i][j],t[l]-j*a);
            }
            l=1;r=0;
            for(rg j=m;j>=0;--j){
                now=f[i-w-1][j]+j*b;
                while(l<=r&&p[l]>j+d)++l;
                while(l<=r&&t[r]<=now)--r;
                t[++r]=now;p[r]=j;
                if(l <= r)f[i][j]=max(f[i][j],t[l]-j*b);
            }
        }
        for(rg j=0;j<=m;++j)
            ans=max(ans,f[n][j]);
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Xcode8 1 创建coreData的ManagedObject后,报错 linker command failed with exit code 1
    在IOS中根据圆心坐标、半径和角度计算圆弧上的点坐标
    NodeJS学习目录
    nodeJS之URL
    nodeJS之域名DNS
    初识nodeJS
    使用nodeJS实现前端项目自动化之项目构建和文件合并
    nodeJS之fs文件系统
    nodeJS之二进制buffer对象
    nodeJS之进程process对象
  • 原文地址:https://www.cnblogs.com/812-xiao-wen/p/11207164.html
Copyright © 2011-2022 走看看