Luogu 2569 SCOI2010 股票交易
Posted shu-kuang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; }
以上是关于Luogu 2569 SCOI2010 股票交易的主要内容,如果未能解决你的问题,请参考以下文章
LUOGU P2569 [SCOI2010]股票交易(单调队列优化dp)