【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. Linux中的 awk查找日志中的相关记录

    假设要在 api.log.201707201830 文件中,(此文件的多个字段数据以不可见字符^A(键盘上按下Ctrl+V+A)分隔),要输出第70个字段: awk -F '^A' '{print $ ...

  2. composer引用本地git做为源库

    PHP使用者大多对composer是又爱又恨,爱的是composer require后,很多类库不用去下载了,恨的是网速卡成翔,虽然国内有很多道友做了镜象,但对于bower库这些都还是整体更新. 那么 ...

  3. According to TLD or attribute directive in tag file, attribute value does not accept any expressions报错解决办法

    1.出现原因: 导入的uri由于不是正确的导致这个jstl不支持el的表达式 jstl uri导入错误:   <%@ taglib prefix="c" uri=" ...

  4. org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: file [/Users/lonecloud/tomcat/apache-tomcat-7.0.70 2/webapps/myproject/WEB-INF/classes/cn/lone

    解决这个报错的解决办法: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidat ...

  5. LNMP搭建环境遇到的N多坑

    最近配置开发用的lnmp环境,环境配置完成后,爆500错误,查看nginx错误日志 open_basedir 将 PHP 所能打开的文件限制在指定的目录树,包括文件本身 错误日志显示,访问脚本不在 o ...

  6. PHP网站的安全要点

    1. 删除不必要的模块 PHP随带内置的PHP模块.它们对许多任务来说很有用,但是不是每个项目都需要它们.只要输入下面这个命令,就可以查看可用的PHP模块: # php - m 一旦你查看了列表,现在 ...

  7. java基础--面对对象

    面对对象--概述 什么是对象? +---->对象可以泛指一切现实中存着的事物 +---->类是对象的抽象集合 什么是面对对象? +--->万物皆对象,面对对象实际就是人与万物接触== ...

  8. MongoDB,分组,聚合

    使用聚合,db.集合名.aggregate- 而不是find 管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数.MongoDB的聚合管道将MongoDB文档在一个管道处理完 ...

  9. mysql常用脚本及命令记录

    mysql导出用户权限 mysql中直接通过授权即可使用对应用户,不必使用创建用户命令(如CREATE USER 'xxx'@'%' IDENTIFIED BY 'XXX';)先建用户再授权. 方法一 ...

  10. 利用Apache配置本地 自定义域名

    第一步:配置 httpd.conf 开启 虚拟主机 配置模块 去掉 " Include conf/extra/httpd-vhosts.conf " 前面的" # &qu ...