BZOJ1855 [Scoi2010]股票交易[单调队列dp]
题面有点复杂,不概括了。
后面的状态有前面的最优解获得大致方向是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]的更多相关文章
- 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 ...
- 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 ...
- 【bzoj1855】 [Scoi2010]股票交易 单调队列优化DP
上一篇blog已经讲了单调队列与单调栈的用法,本篇将讲述如何借助单调队列优化dp. 我先丢一道题:bzoj1855 此题不难想出O(n^4)做法,我们用f[i][j]表示第i天手中持有j只股票时,所赚 ...
- 1855: [Scoi2010]股票交易[单调队列优化DP]
1855: [Scoi2010]股票交易 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1083 Solved: 519[Submit][Status] ...
- LUOGU P2569 [SCOI2010]股票交易(单调队列优化dp)
传送门 解题思路 不难想一个\(O(n^3)\)的\(dp\),设\(f_{i,j}\)表示第\(i\)天,手上有\(j\)股的最大收益,因为这个\(dp\)具有单调性,所以\(f_i\)可以贪心的直 ...
- luogu 2569 股票交易 单调队列dp
注意转移方程 分1.凭空买 2.不买不卖 3.在原来基础上买 4.在原来基础上卖 四种情况 head=1,tail=0;再判断一下head<=tail也可以 #include<bits/s ...
- POJ 3017 单调队列dp
Cut the Sequence Time Limit: 2000MS Memory Limit: 131072K Total Submissions: 8764 Accepted: 2576 ...
- [TyvjP1313] [NOIP2010初赛]烽火传递(单调队列 + DP)
传送门 就是个单调队列+DP嘛. ——代码 #include <cstdio> ; , t = , ans = ~( << ); int q[MAXN], a[MAXN], f ...
- zstu 4237 马里奥的求救——(单调队列DP)
题目链接:http://oj.acm.zstu.edu.cn/JudgeOnline/problem.php?id=4237 这题可以转化为每次可以走g~d+x步,求最大分数,且最大分数的步数最少. ...
随机推荐
- android一步一步实现视频clientapp(一)
我开发完毕了一个完整的视频clientapp.如今.分享出来.供刚開始学习的人学习參考(大神就不用看了,比較简单,仅供入门),大家相互交流相互学习. 项目有些功能,我时间也不是非常多.仅仅能时不时更新 ...
- Scrapy教程
Scrapy教程 原文地址https://doc.scrapy.org/en/latest/intro/tutorial.html 此教程我们假设你已经装好了Scrapy,如果没有请查看安装指南.. ...
- 手把手实现andriod应用增量升级
近期研究了android应用增量升级的应用.当中用到了android NDK编程,先说下为什么要使用增量升级.当我们的应用达到一定大小的时候,比方眼下有30M.假设新版本号35M仅仅是添加了几个功能, ...
- php 导出CSV抽象类
php 导出CSV抽象类,依据总记录数与每批次记录数,计算总批次.循环导出.避免内存不足的问题. ExportCSV.class.php <? php /** php Export CSV ab ...
- ASP.NET MVC路径引用总结
1.关于路径: (1)绝对路径 包含站点路径的路径:<a href=”http://www.baidu.com/about.jpg”>百度</a> 站点改变路径失效: (2)相 ...
- 讲真,你是因为什么才买华为P20系列手机!
华为P20系列手机上市两个半月发货600万台!600万台?!看到这个亮瞎我钛合金狗眼的数据,且容我掰着手指脚趾算一下,算了,还是容我毫不夸张的感叹一句吧:华为做手机不用桨,不需风,全靠“浪”……. 两 ...
- 美景听听Ai语音导游,助力华为荣耀PLAY手机发布
6月6日,荣耀PLAY科技酷玩新品发布会在北京大学生体育馆如期举办,美景听听Ai语音讲解助力新EUMI系统智慧旅行成新卖点,震撼登场! 随着生活水平的不断提升,出门旅行已经成了许多亲们释放压力.调节自 ...
- nginx - KeepAlive详细解释
最近工作中遇到一个问题,想把它记录下来,场景是这样的: 从上图可以看出,用户通过Client访问的是LVS的VIP, VIP后端挂载的RealServer是Nginx服务器. Client可以是浏览器 ...
- C#与Java在修饰符上的不同
1.readonly 修饰符仅用于修饰类的数据成员.正如其名字说的,一旦它们已经进行了写操作.直接初始化或在构造函数中对其进行了赋值,数据成员就只能对其进行读取. readonly 和 const 数 ...
- 百思不得姐之"我的"模块功能(六)
一 功能图和知识点 1 功能图部分:(因为网速的原因,网页部分没有载入出来,可是功能完善) 2 该部分能学到的知识点概括: >1 UITableView的使用(简单) >2 UIColle ...