【BZOJ1855】股票交易(动态规划,单调队列)
【BZOJ1855】股票交易(动态规划,单调队列)
题面
题解
很显然,状态之和天数以及当天剩余的股票数有关
设\(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】股票交易(动态规划,单调队列)的更多相关文章
- 【BZOJ1855】[Scoi2010]股票交易 DP+单调队列
[BZOJ1855][Scoi2010]股票交易 Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预 ...
- BZOJ1855 [Scoi2010]股票交易 【单调队列优化dp】
题目链接 BZOJ1855 题解 设\(f[i][j]\)表示第\(i\)天结束时拥有\(j\)张股票时的最大收益 若\(i \le W\),显然在这之前不可能有交易 \[f[i][j] = max\ ...
- 2018.09.10 bzoj1855: [Scoi2010]股票交易(单调队列优化dp)
传送门 单调队列优化dp好题. 有一个很明显的状态设置是f[i][j]表示前i天完剩下了j分股票的最优值. 显然f[i][j]可以从f[i-w-1][k]转移过来. 方程很好推啊. 对于j<kj ...
- 洛谷P2569 (BZOJ1855)[SCOI2010]股票交易 【单调队列优化DP】
Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价 ...
- 股票交易 (单调队列优化DP)
股票交易 $ solution: $ 这道题以前就写了,题目很好,但自己没有发题解,来补一篇: 首先,题目出得很有迷惑性,但我们不难想到状态要设天数,和自己手上的股票数目(因为这两个就是充要信息).而 ...
- P2569 [SCOI2010]股票交易 dp 单调队列优化
LINK:股票交易 题目确实不算难 但是坑点挺多 关于初值的处理问题我就wa了两次. 所以来谢罪. 由于在手中的邮票的数量存在限制 且每次买入卖出也有限制. 必然要多开一维来存每天的邮票数量. 那么容 ...
- BZOJ 1855 股票交易(单调队列优化DP)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1855 题意:最近lxhgww又迷上了投资股票, 通过一段时间的观察和学习,他总结出了股票 ...
- BZOJ_1096_[ZJOI2007]_仓库建设_(斜率优化动态规划+单调队列+特殊的前缀和技巧)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1096 有\(n\)个工厂,给出第\(i\)个工厂的到1号工厂的距离\(x[i]\),货物数量\ ...
- BZOJ_1010_[HNOI2008]_玩具装箱toy_(斜率优化动态规划+单调队列)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1010 给出\(n\)和\(l\).有\(n\)个玩具,第\(i\)个玩具的长度是\(c[i]\ ...
- UOJ#172. 【WC2016】论战捆竹竿 字符串 KMP 动态规划 单调队列 背包
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ172.html 题解 首先,这个问题显然是个背包问题. 然后,可以证明:一个字符串的 border 长度可 ...
随机推荐
- python 路飞模块一考核总结
1. 分别解释"=","==","+="的含义(口述) =为赋值语句,把一个变量值赋予另一个值 == 为条件判断,判断两个值是否相等 += ...
- 关于 IO的同步异步间要描述
IO在计算机中指Input/Output,也就是输入和输出.由于程序和运行时数据是在内存中驻留,由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘.网络等,就需要IO接口. 比如你打开 ...
- Gitbucket—快速建立自己的Github
GitBucket是一个用Scala语言编写的类似Github的应用,界面非常相似.它非常容易安装–容易到你只需要把它的war文件扔到tomcat中,然后启动tomcat就直接可以访问了.或者直接ja ...
- zabbix客户端一键安装脚本
#!/bin/bash #通过命令行参数指定if [ ! -z "$1" ];then ip=$1 echo "手动指定IP:$ip"else#根据默认路由获取 ...
- 置换群、Burnside引理与等价类计数问题
置换群.Burnside引理与等价类计数问题 标签: 置换群 Burnside引理 置换 说说我对置换的理解,其实就是把一个排列变成另外一个排列.简单来说就是一一映射.而置换群就是置换的集合. 比如\ ...
- 【深度学习系列】用PaddlePaddle进行车牌识别(一)
小伙伴们,终于到了实战部分了!今天给大家带来的项目是用PaddlePaddle进行车牌识别.车牌识别其实属于比较常见的图像识别的项目了,目前也属于比较成熟的应用,大多数老牌厂家能做到准确率99%+.传 ...
- Git环境配置+VSCode中文乱码问题
异常处理汇总-开发工具 http://www.cnblogs.com/dunitian/p/4522988.html 1.VSCode中文乱码问题 (files.autoguessEncoding= ...
- 对TCP三次握手四次分手还不清楚的速度进,超简单解析,明白了就很好记!
关于TCP三次握手四次分手,之前看资料解释的都很笼统,很多地方都不是很明白,所以很难记,前几天看的一个博客豁然开朗,可惜现在找不到了.现在把之前的疑惑总结起来,方便一下大家. 先上个TCP三次握手和四 ...
- iOS实现从服务器请求json数据并转化成NSDictionary
NSURL *url = [NSURL URLWithString:URL]; NSURLRequest *request = [NSURLRequest requestWithURL:url cac ...
- Django在form提交CSRF验证失败. 相应中断问题
CSRF验证失败. 相应中断. 1).首先,我们可以先看一下出现问题的所在的原因. Your browser is accepting cookies. The view function passe ...