【BZOJ1855】股票交易(动态规划,单调队列)

题面

BZOJ

题解

很显然,状态之和天数以及当天剩余的股票数有关

设\(f[i][j]\)表示第\(i\)天进行了交易,剩余股票数为\(j\)的最大获利

每次枚举可以转移过来的天数以及股票数

再枚举买入或者卖出的数量,

时间复杂度\(O(T^2Mp^2)\),30pts(但是有40pts。。。)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 2222
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int T,Mp,W;
int f[MAX][MAX];
int vb[MAX],vs[MAX],lb[MAX],ls[MAX];
int main()
{
T=read();Mp=read();W=read();
for(int i=1;i<=T;++i)
{
vb[i]=read();vs[i]=read();
lb[i]=read();ls[i]=read();
}
memset(f,-63,sizeof(f));
f[0][0]=0;
for(int i=1;i<=T;++i)
{
for(int j=0;j<=max(i-W-1,0);++j)
{
for(int k=0;k<=Mp;++k)
{
for(int l=1;k+l<=Mp&&l<=lb[i];++l)
f[i][k+l]=max(f[i][k+l],f[j][k]-l*vb[i]);
for(int l=1;l<=k&&l<=ls[i];++l)
if(l<=k)f[i][k-l]=max(f[i][k-l],f[j][k]+l*vs[i]);
}
}
}
int ans=0;
for(int i=1;i<=T;++i)ans=max(ans,f[i][0]);
printf("%d\n",ans);
return 0;
}

其实没有任何必要枚举可以转移过来的天数

把状态稍微改变一下

设\(f[i][j]\)表示第\(i\)天拥有的股票数为\(j\)的最大获利

每次可以从\(f[i-1]\)转移过来

这样只需要枚举交易的限制天数前就行了

复杂度\(O(TMp^2)\),50pts

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 2222
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int T,Mp,W;
int f[MAX][MAX];
int vb[MAX],vs[MAX],lb[MAX],ls[MAX];
int main()
{
T=read();Mp=read();W=read();
for(int i=1;i<=T;++i)
{
vb[i]=read();vs[i]=read();
lb[i]=read();ls[i]=read();
}
memset(f,-63,sizeof(f));
int ttt=f[0][0];
f[0][0]=0;
for(int i=1;i<=T;++i)
{
int j=max(0,i-W-1);
for(int k=0;k<=Mp;++k)
{
f[i][k]=max(f[i][k],f[i-1][k]);
for(int l=1;k+l<=Mp&&l<=lb[i];++l)
f[i][k+l]=max(f[i][k+l],f[j][k]-l*vb[i]);
for(int l=1;l<=k&&l<=ls[i];++l)
if(l<=k)f[i][k-l]=max(f[i][k-l],f[j][k]+l*vs[i]);
}
}
printf("%d\n",f[T][0]);
return 0;
}

听说数据比较水,50pts稍微优化一下可以卡过70pts

70pts:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 2222
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int T,Mp,W;
int f[MAX][MAX];
int vb[MAX],vs[MAX],lb[MAX],ls[MAX];
int main()
{
T=read();Mp=read();W=read();
for(int i=1;i<=T;++i)
{
vb[i]=read();vs[i]=read();
lb[i]=read();ls[i]=read();
}
memset(f,-63,sizeof(f));
f[0][0]=0;
for(int i=1;i<=T;++i)
{
for(int j=0;j<=lb[i];++j)f[i][j]=-j*vb[i];
for(int j=0;j<=Mp;++j)f[i][j]=max(f[i][j],f[i-1][j]);
if(i<=W)continue;
int j=i-W-1;
for(int k=0;k<=Mp;++k)
{
for(int l=1;k+l<=Mp&&l<=lb[i];++l)
f[i][k+l]=max(f[i][k+l],f[j][k]-l*vb[i]);
for(int l=1;l<=k&&l<=ls[i];++l)
if(l<=k)f[i][k-l]=max(f[i][k-l],f[j][k]+l*vs[i]);
}
}
printf("%d\n",f[T][0]);
return 0;
}

这个复杂度已经跑不了了

怎么解决转移的复杂度问题?

对于从\(W\)天(第\(x\)天)前购买/出售的转移

我们额外看看:

\(f[i][j]=max(f[x][k]+k*V-j*V)\)

貌似和\(j\)没什么关系诶

\(f[i][j]=max(f[x][k]+k*V)-j*V\)

这样就可以单调队列优化转移了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 2222
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int T,Mp,W;
int f[MAX][MAX];
int vb[MAX],vs[MAX],lb[MAX],ls[MAX];
int l,r,Q[MAX];
int main()
{
T=read();Mp=read();W=read();
for(int i=1;i<=T;++i)
{
vb[i]=read();vs[i]=read();
lb[i]=read();ls[i]=read();
}
memset(f,-63,sizeof(f));
f[0][0]=0;
for(int i=1;i<=T;++i)
{
for(int j=0;j<=lb[i];++j)f[i][j]=-j*vb[i];
for(int j=0;j<=Mp;++j)f[i][j]=max(f[i][j],f[i-1][j]);
if(i<=W)continue;
int x=i-W-1,h,t;
h=1,t=0;
for(int j=0;j<=Mp;++j)
{
while(h<=t&&Q[h]<j-lb[i])++h;
while(h<=t&&f[x][Q[t]]+Q[t]*vb[i]<=f[x][j]+j*vb[i])--t;
Q[++t]=j;
if(h<=t)f[i][j]=max(f[i][j],f[x][Q[h]]+Q[h]*vb[i]-j*vb[i]);
}
h=1,t=0;
for(int j=Mp;j>=0;--j)
{
while(h<=t&&Q[h]>j+ls[i])++h;
while(h<=t&&f[x][Q[t]]+Q[t]*vs[i]<=f[x][j]+j*vs[i])--t;
Q[++t]=j;
if(h<=t)f[i][j]=max(f[i][j],f[x][Q[h]]+Q[h]*vs[i]-j*vs[i]);
} }
printf("%d\n",f[T][0]);
return 0;
}

【BZOJ1855】股票交易(动态规划,单调队列)的更多相关文章

  1. 【BZOJ1855】[Scoi2010]股票交易 DP+单调队列

    [BZOJ1855][Scoi2010]股票交易 Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预 ...

  2. BZOJ1855 [Scoi2010]股票交易 【单调队列优化dp】

    题目链接 BZOJ1855 题解 设\(f[i][j]\)表示第\(i\)天结束时拥有\(j\)张股票时的最大收益 若\(i \le W\),显然在这之前不可能有交易 \[f[i][j] = max\ ...

  3. 2018.09.10 bzoj1855: [Scoi2010]股票交易(单调队列优化dp)

    传送门 单调队列优化dp好题. 有一个很明显的状态设置是f[i][j]表示前i天完剩下了j分股票的最优值. 显然f[i][j]可以从f[i-w-1][k]转移过来. 方程很好推啊. 对于j<kj ...

  4. 洛谷P2569 (BZOJ1855)[SCOI2010]股票交易 【单调队列优化DP】

    Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价 ...

  5. 股票交易 (单调队列优化DP)

    股票交易 $ solution: $ 这道题以前就写了,题目很好,但自己没有发题解,来补一篇: 首先,题目出得很有迷惑性,但我们不难想到状态要设天数,和自己手上的股票数目(因为这两个就是充要信息).而 ...

  6. P2569 [SCOI2010]股票交易 dp 单调队列优化

    LINK:股票交易 题目确实不算难 但是坑点挺多 关于初值的处理问题我就wa了两次. 所以来谢罪. 由于在手中的邮票的数量存在限制 且每次买入卖出也有限制. 必然要多开一维来存每天的邮票数量. 那么容 ...

  7. BZOJ 1855 股票交易(单调队列优化DP)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1855 题意:最近lxhgww又迷上了投资股票, 通过一段时间的观察和学习,他总结出了股票 ...

  8. BZOJ_1096_[ZJOI2007]_仓库建设_(斜率优化动态规划+单调队列+特殊的前缀和技巧)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1096 有\(n\)个工厂,给出第\(i\)个工厂的到1号工厂的距离\(x[i]\),货物数量\ ...

  9. BZOJ_1010_[HNOI2008]_玩具装箱toy_(斜率优化动态规划+单调队列)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1010 给出\(n\)和\(l\).有\(n\)个玩具,第\(i\)个玩具的长度是\(c[i]\ ...

  10. UOJ#172. 【WC2016】论战捆竹竿 字符串 KMP 动态规划 单调队列 背包

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ172.html 题解 首先,这个问题显然是个背包问题. 然后,可以证明:一个字符串的 border 长度可 ...

随机推荐

  1. SparkSteaming运行流程分析以及CheckPoint操作

    本文主要通过源码来了解SparkStreaming程序从任务生成到任务完成整个执行流程以及中间伴随的checkpoint操作 注:下面源码只贴出跟分析内容有关的代码,其他省略 1 分析流程 应用程序入 ...

  2. weblogic修改jdk版本遇到的问题与解决方法

    1.修改setDomainEnv ,路径.../domains/xx_domain\bin\ 1.1修改JAVA_HOME为需要修改的路径 注意:BEA_JAVA_HOME路径不需修改 2.修改路径后 ...

  3. golang 实现简单的一致性哈希

    package main import ( "fmt" "sort" "hash/crc32" ) var serverMap map[ui ...

  4. hdu4143 A Simple Problem

    A Simple Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) ...

  5. iOS 添加WKWebView导致控制器无法释放的问题

    在WkWebView与JavaScript交互中,经常会在原生中注入MessageHandler,app中注入MessageHandler的方法 WKWebViewConfiguration *con ...

  6. 【netty这点事儿】ByteBuf 的使用模式

    堆缓冲区 最常用的 ByteBuf 模式是将数据存储在 JVM 的堆空间中. 这种模式被称为支撑数组(backing array), 它能在没有使用池化的情况下提供快速的分配和释放. 直接缓冲区 直接 ...

  7. WEB服务器防盗链_HttpAccessKeyModule_Referer(Nginx&&PHP)

    盗链的概念指在自己的页面上展示一些并不在自己服务器上的内容.也就是获得他人服务器上的资源地址,绕过别人的资源展示页面,直接在自己的页面上向最终用户提供此内容.如,小站盗用大站的图片.音乐.视频.软件等 ...

  8. POJ - 1733 Parity game 种类并查集+离散化

    思路:d(i, j)表示区间(i, j]的1的个数的奇偶性.输入最多共有5000*2个点,需要离散化处理一下.剩下的就是并查集判冲突. AC代码 #include <cstdio> #in ...

  9. 《python机器学习—预测分析核心算法》笔记1

    参见原书 1.1-1.4节 一.惩罚线性回归模型 基本特性: 1.训练时间快,使用训练好的模型进行预测的时间也快2.应用于高速交易.互联网广告的植入等3.解决回归.分类问题 最重要的特性:能明确指出, ...

  10. [Note] Stream Computing

    Stream Computing 概念对比 静态数据和流数据 静态数据,例如数据仓库中存放的大量历史数据,特点是不会发生更新,可以利用数据挖掘技术和 OLAP(On-Line Analytical P ...