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步,求最大分数,且最大分数的步数最少. ...
随机推荐
- C# 请求Web Api 接口,返回的json数据直接反序列化为实体类
须要的引用的dll类: Newtonsoft.Json.dll.System.Net.Http.dll.System.Net.Http.Formatting.dll Web Api接口为GET形式: ...
- INSTALL_FAILED_UID_CHANGED解决的方法
近期开发过程中又遇到了这个问题,最终找到了一个比較好的解决的方法.在此记录下. 打开手机或者pad中的设置----->安全----->未知来源(同意安装非安卓市场应用程序). 把这个取消, ...
- 笔记本中G-Sensor(加速计) M-Sensor 陀螺仪等传感器的区别
1.G-sensor重力传感器 作用 G-sensor中文是加速度传感器的意思(英文全称是Accelerometer-sensor),它能够感知到加速力的变化,加速力就是当物体在加速过程中作用在物体上 ...
- wampserver 安装多个php版本号报错之关键问题
近期喜欢上用wampserver来搭建php本地执行环境 主要是一键安装 特easy 之前一直用的是 appserv 也挺好用的 用了wamp后 才发现wamp更好用 duang duang 默认下载 ...
- oracle中视图V$PGA_TARGET_ADVICE的用法
看一下这个视图能给我们带来什么样的信息(视图中每个列都很有帮助):sys@ora10g> SELECT pga_target_for_estimate / 1024 / 1024 " ...
- Mac Security工具使用总结find-identity
Security是Mac系统中钥匙串和安全模块的命令行管理工具,(图形化工具为Keychain Access.app).钥匙串(Keychain)实质上就是一个用于存放证书.密钥.密码等安全认证实体的 ...
- 关于 Swift 的一点初步看法
本文转自:http://onevcat.com/2014/06/my-opinion-about-swift/ 感谢原作者 尽管四点半就起床去排队等入场,结果还是仅仅能坐在了蛮后面的位置看着大屏幕參加 ...
- C#泛型<T>说明
泛型:即通过参数化类型来实现在同一份代码上操作多种数据类型.泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用. C#泛型的作用概述 C#泛型赋予了代码更强的类型安全,更 ...
- LA 3882 And Then There Was One[约瑟夫问题的变形]
And Then There Was One UVALive - 3882 Sample Input Sample Output //设f[i]为(原约瑟夫问题)第i次要删除的标号 #includ ...
- 【BZOJ4373】算术天才⑨与等差数列 线段树+set
[BZOJ4373]算术天才⑨与等差数列 Description 算术天才⑨非常喜欢和等差数列玩耍.有一天,他给了你一个长度为n的序列,其中第i个数为a[i].他想考考你,每次他会给出询问l,r,k, ...