题面有点复杂,不概括了。


后面的状态有前面的最优解获得大致方向是dp。先是瞎想了个$f[i][j]$表示第$i$天手里有$j$张股票时最大收入(当天无所谓买不买)。

然后写了一个$O(n^4)$状转

$f[i][j]=max(max\{f[k][l]-(j-l)*AP[i]\},max\{f[k][l]+(l-j)*BP[i]\})$

这个很明显就是某一天的前w天之前是可以交易后推到这一天的,因为$i-w~i-1$这些天的状态你也不知道最优解有没有在当天进行交易。那就分为买和卖股票两部分,分别算一下最大利益再合并就行,注意保留不买也不卖的状态。买和卖每天的数量限制就转化为范围。注意题目的意思,一天也是可以既买入又卖出股票的,但是可以发现我们有一部分股票可算作卖出又买回来,这样坑定要亏,那不如不卖了,所以每天要不然买,要不然卖,要不然什么也不做

验证正确性,写了个40pts暴力

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define dbg(x) cerr<<#x<<"="<<x<<endl
using namespace std;
typedef long long ll;
template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=+;const ll INF=1e13;
ll f[N][N],ans;
int n,m,w,as,bs,ap,bp; int main(){//freopen("test.in","r",stdin);//freopen("tmp.out","w",stdout);
read(n),read(m),read(w);
for(register int i=;i<=m;++i)f[][i]=-INF;
for(register int i=;i<=n;++i){
read(ap),read(bp),read(as),read(bs);
for(register int j=;j<=m;++j){
f[i][j]=-INF;
for(register int k=;k<=_max(,i-w-);++k){
for(register int l=_max(,j-as);l<=j;++l)if(f[k][l]^-INF)MAX(f[i][j],f[k][l]-(j-l)*1ll*ap);
for(register int l=j+;l<=_min(m,j+bs);++l)if(f[k][l]^-INF)MAX(f[i][j],f[k][l]+(l-j)*1ll*bp);
}
MAX(ans,f[i][j]);
}
}
printf("%lld\n",ans);
return ;
}

好下面想优化。观察到每一行的每一格算卖出的最大利润可以有前面一些行从这一列开始往后的一块选max转移过来,所以卖出可以倒推dp。我可以分列转移,每一列$l$可行的$k∈[1~i-w-1]$天内找一个$max\{f[k][l]+(l-j)*b\}$即$max\{f[k][l]\}+(l-j)*b$,那我只需要每列维护一个单调栈,保持栈底是j列的f最大值,然后每列直接转移.复杂度$O(n^3)$。再看我每一格是由后面的$bs[i]$格所在列转移的,每列我已经找到一个最优解,那下面我要从这几列(范围内)内找$max\{f[l]+(l-j)*b\}$($f[l]$为l这一列最大f值)即$max\{f[l]+l*b\}-j*b$,这时就可以用单调队列维护max内那玩意儿了。每行做一次,买入转态同理,从前往后做一遍。同样注意不买不卖的情况应予以保留。复杂度就成了$O(n^2)$。细节看垃圾代码

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define dbg(x) cerr<<#x<<"="<<x<<endl
using namespace std;
typedef long long ll;
template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=+;const ll INF=1e13;
ll f[N][N],ans;
int q[N],qb[N][N],qa[N][N],ta[N],tb[N];//t--stack's top
int n,m,w,a,b,A,B,l,r;//a--buy b--sell A--buying Bmax stocks B--selling Smax stocks
inline ll Fb(int j,int b){return f[qb[j][]][j]+1ll*j*b;}
inline ll Fa(int j,int a){return f[qa[j][]][j]+1ll*j*a;} int main(){//freopen("test.in","r",stdin);//freopen("tmp.out","w",stdout);
read(n),read(m),read(w);
for(register int j=;j<=m;++j)f[][j]=-INF;f[][]=;
for(register int i=;i<=n;++i){
read(a),read(b),read(A),read(B);
for(register int j=;j<=m;++j)f[i][j]=-INF;
l=,r=;
for(register int j=m;~j;--j){
if(i>w+){
while(tb[j]&&f[qb[j][tb[j]]][j]<=f[i-w-][j])--tb[j];
qb[j][++tb[j]]=i-w-;
}
while(l<=r&&Fb(q[r],b)<=Fb(j,b))--r;
q[++r]=j;
while(l<=r&&q[l]>j+B)++l;
MAX(f[i][j],Fb(q[l],b)-1ll*j*b);
}
l=,r=;
for(register int j=;j<=m;++j){
if(i>w+){
while(ta[j]&&f[qa[j][ta[j]]][j]<=f[i-w-][j])--ta[j];
qa[j][++ta[j]]=i-w-;
}
while(l<=r&&Fa(q[r],a)<=Fa(j,a))--r;
q[++r]=j;
while(l<=r&&q[l]<j-A)++l;
MAX(f[i][j],Fa(q[l],a)-1ll*j*a);
MAX(ans,f[i][j]);
}
}
printf("%lld\n",ans);
return ;
}

嗯上边的思路是我个人想的,有部分地方想繁掉了,于是A掉之后看了一眼题解,发现自己真傻。。单调栈完全没必要开出来的。

我要找每一列的合法最大值转移,不用单调栈维护,只要在$f[i-w-1][j]$直接从$f[i-w-2][j]$继承过来就好了,也不会影响合法性,我前一天做了交易,今天不动,所以没事,这样我在这里就保留了j这一列最大f值,因为它来自于上面数行中$fmax$和当前行dp取得的f的最大值。所以一开始朴素方程就是$O(n^3)$的。这个继承获得之前最大值的办法希望记住。

BZOJ1855 [Scoi2010]股票交易[单调队列dp]的更多相关文章

  1. bzoj1855: [Scoi2010]股票交易--单调队列优化DP

    单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w ...

  2. bzoj1855: [Scoi2010]股票交易 单调队列优化dp ||HDU 3401

    这道题就是典型的单调队列优化dp了 很明显状态转移的方式有三种 1.前一天不买不卖: dp[i][j]=max(dp[i-1][j],dp[i][j]) 2.前i-W-1天买进一些股: dp[i][j ...

  3. 【bzoj1855】 [Scoi2010]股票交易 单调队列优化DP

    上一篇blog已经讲了单调队列与单调栈的用法,本篇将讲述如何借助单调队列优化dp. 我先丢一道题:bzoj1855 此题不难想出O(n^4)做法,我们用f[i][j]表示第i天手中持有j只股票时,所赚 ...

  4. 1855: [Scoi2010]股票交易[单调队列优化DP]

    1855: [Scoi2010]股票交易 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1083  Solved: 519[Submit][Status] ...

  5. LUOGU P2569 [SCOI2010]股票交易(单调队列优化dp)

    传送门 解题思路 不难想一个\(O(n^3)\)的\(dp\),设\(f_{i,j}\)表示第\(i\)天,手上有\(j\)股的最大收益,因为这个\(dp\)具有单调性,所以\(f_i\)可以贪心的直 ...

  6. luogu 2569 股票交易 单调队列dp

    注意转移方程 分1.凭空买 2.不买不卖 3.在原来基础上买 4.在原来基础上卖 四种情况 head=1,tail=0;再判断一下head<=tail也可以 #include<bits/s ...

  7. POJ 3017 单调队列dp

    Cut the Sequence Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8764   Accepted: 2576 ...

  8. [TyvjP1313] [NOIP2010初赛]烽火传递(单调队列 + DP)

    传送门 就是个单调队列+DP嘛. ——代码 #include <cstdio> ; , t = , ans = ~( << ); int q[MAXN], a[MAXN], f ...

  9. zstu 4237 马里奥的求救——(单调队列DP)

    题目链接:http://oj.acm.zstu.edu.cn/JudgeOnline/problem.php?id=4237 这题可以转化为每次可以走g~d+x步,求最大分数,且最大分数的步数最少. ...

随机推荐

  1. 30:根据排序标识flag给数组排序

    题目描述:输入整型数组和排序标识,对其元素按照升序或降序进行排序 接口说明 原型: void sortIntegerArray(Integer[] pIntegerArray, int iSortFl ...

  2. Scrapy安装向导

    原文地址 https://doc.scrapy.org/en/latest/intro/install.html 安装Scrapy Scrapy运行在python2.7和python3.3或以上版本( ...

  3. Shell脚本笔记 1

    函数别名 设置别名 alias name="command" alias ll="ls -laS" 取消别名 unalias name 求取数学表达式 valu ...

  4. ubuntu16.04----jdk---install----config

    1.下载jdk. 2.验证java是否安装,使用java -version命令,如下图所示说明没有安装: 3.在usr目录中创建一个jdk-8目录,如下图所示: 4.配置系统环境变量,编辑/etc/p ...

  5. substring,subsequence,charAt执行效率的不同

    package com.java.tencent; public class T_2_longestPalindrome { public String test1(String s){ long s ...

  6. 【Unity3D】【NGUI】Atlas的动态创建

    NGUI版本号:3.6.5 1.參见SZUIAtlasMakerRuntimeTest设置对应的值以上值须要提前设置好 2.没有检查是否atlas可以正确创建,自己可以改,增加返回值 3.代码都是在N ...

  7. 输入一个n,输出2到n的详细素数值

    #include<stdio.h> #include<algorithm> #include<cmath> int judge(int a) { int j; fo ...

  8. ssh无密码登陆权威指南

    [0]写在前面 由于ssh 实现的是免密码登陆,大致步骤是: 0.1) client通过ssh登陆到server: 0.2) server检查家目录下的.ssh文件, 并发送公钥文件 authoriz ...

  9. GS与网络打交道

    与网络打交道 在GS,GC,Share都与网络打交道,但还是GC最多 GC打交道过程 send_stat BaseChannel::SendCmdTry() { if (!m_queCmd.size( ...

  10. Unix环境高级编程—进程控制(三)

    一.解释器文件 解释器文件属于文本文件,起始行形式为: #! pathname[optional-argument] 我们创建一个只有一行的文件如下: #!/home/webber/test/echo ...