zoukankan      html  css  js  c++  java
  • Luogu 2569 SCOI2010 股票交易

    题面

    这个题状态设计和状态转移方程都非常好设计好推,重点思考一下单调队列优化以及代码DP中一些初始化,转移要点的一些方法,尽量做到以后不再犯类似的错误。

    F[i][j] 即第i天,当前手中有j的股票所能带来的最大价值。

    分类讨论一下,今天可以买,可以不买,还可以卖。

    买的话可以分为我今天第一次开始买(是不是发现它其实就是初始化),和以前买过了,这就需要从先前的转移过来了。

    不买就直接取Max

    卖掉的话就枚举一下卖了多少,然后看一下可以收益的最大价值。

    这里就可以体现一个很有用的思想,既然总是初始化有问题,就可以把初始化部分也归为一个转移来讨论,就像本题中这样,这样我们讨论当前天买股票时以前没买过,自然也就是初始化了。

    在转移买股票的时候要注意一下股票持有数量的范围的枚举,既然当前天是以前卖过的,我们的K值是在这个J值上单调向右滑的,以前的K值较大,所以我们肯定要让左边的小一些。

    然后单调队列里面维护的就是这个K值,注意在单调队列维护完之后转移方程写原方程中,把原来的K变成对头就行了。

    代码:

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 2020;
    int T, MaxP, W;
     
    int ap[N], bp[N], as[N], bs[N], ans;
    //在第i天的时候,手上持有j股票,
    int f[N][N];
    
    //最近DP写的总是推的出式子,其他各种各样出问题
    
    int q[N];//单调队列优化
    int h, t;
    int main(){
        scanf("%d %d %d", &T, &MaxP, &W);
        for(int i = 1;i <= T;++ i)
        scanf("%d %d %d %d", &ap[i], &bp[i], &as[i], &bs[i]);
        memset(f, 128, sizeof f);//求Max,而且初始买票需要花钱,所以赋值成负无穷
        for(int i = 1;i <= T;++ i){
            for(int j = 0;j <= as[i];++ j){//buy  today
                f[i][j] = -1 * j * ap[i];
            }
            for(int j = MaxP;j >= 0;-- j)
            f[i][j] = max(f[i][j], f[i-1][j]);//正序倒序无所谓
            if(i - W - 1 <= 0) continue;
            //单调队列的话我们可以这么考虑,我们优化完毕之后
            //发现k满足单调性以及维护的一坨是和k相关的,所以我们可以在
            //队列里面维护的东西就是当前今天的这个k值,更新一下
            h = 1,t = 0;
            for(int j = 0;j <= MaxP;++ j){  
                while(h <= t && f[i-W-1][q[t]] + ap[i] * q[t] <= f[i-W-1][j] + ap[i] * j)
                t --;
                q[++t] = j;
                while(h <= t && q[h] < j - as[i])//对头过时了,买这么多也买不着
                h ++;
                if(h <= t) f[i][j] = max(f[i][j], f[i-W-1][q[h]] - ap[i] * (j - q[h]));
            }
            h = 1,t = 0;
            for(int j = MaxP;j >= 0;-- j){
                while(h <= t && f[i-W-1][q[t]] + bp[i] * q[t] <= f[i-W-1][j] + bp[i] * j)
                t --;
                q[++ t] = j;
                while(h <= t && q[h] > j + bs[i]) 
                h ++;
                if(h <= t) f[i][j] = max(f[i][j], f[i-W-1][q[h]] + bp[i] * (q[h] - j));
            }
            /*for(int j = 0;j <= MaxP;++ j){
                f[i][j] = max(f[i-1][j], f[i][j]);//didn' buy anything
                for(int k = 0;k <= MaxP;++ k){//k was last money, j is now
                    if(i <= W) continue;
                    if(j - k <= as[i])
                    f[i][j] = max(f[i][j],f[i-W-1][k] - ap[i] * (j - k));
                    //F[i][j] = max(f[i-W-1][k] - ap[i]*j + ap[i][k]);
                    //F[i][j] = max(f[i-W-1][k] + ap[i]*k) - ap[i]*j;
                    //j - as[i] <= k < j 单调性来了
                    if(k - j <= bs[i])
                    f[i][j] = max(f[i][j],f[i-W-1][k] + bp[i] * (k - j));
                    //F[i][j] = max(f[i-W-1][k] + bp[i]k - bp[i]j);
                    //F[i][j] = max(f[i-W-1][k] + bp[i]*k) - bp[i]*j;
                    //j < k <= j + bs[i] 单调性 
                }
            */
            }
        ans = 0;
        for(int i = 0;i <= MaxP;++ i)
        ans = max(ans, f[T][i]);
        printf("%d", ans);
        return 0;
    }
  • 相关阅读:
    java Boolean和boolean的区别
    stack.isEmpty()和empty()
    mysql中文、英文别名排序问题,order by 关键字详解
    数组中array==null和array.length==0的区别
    7.9总结
    7.8总结
    6.25总结
    6.27总结
    6.29总结
    6.28总结
  • 原文地址:https://www.cnblogs.com/Shu-Kuang/p/12828933.html
Copyright © 2011-2022 走看看