Luogu P2569 [SCOI2010] 股票交易
此题链接到dp常见优化方法
开始的时候被纪念品误导,以为是多支股票,后来发现事情不妙:

这道题知道的是某一只股票的走势;
\(Solution\):
\(70pts\):
设\(f[i][j]\)表示第i天持有j股股票可以获得的最大利润,有如下转移方程:
\(f[i][j]=Max\begin{cases}f[i-1][j] \ \ \ \ //第i天不买也不卖 \\-Ap[i]*j\ \ \ // 第i天之前不持有股票,第i天买入j股股票 \\f[i-w-1][k]-Ap[i]*(j-k) \ \ \ Max(0,j-As[i])\leq k< j \ \ //第i天买入j-k股股票 \\f[i-w-1][k]+Bp[i]*(k-j)\ \ \ j<k\leq Min(MaxP,j+Bs[i]);\ \ //第i天卖出k-j股股票 \end{cases}\)
为什么转移是第\(i-w-1\)天而不是第\(i-w-2\)亦或其它日子呢?
借用一段话(原文:
看第一种情况(第i天不买也不卖),我们已经把某一天以前的最优答案转移到了该天,所以从那一天转移,相当于从那一天包括前面任何一天开始转移,省去了大把时间。
利用上面的四个式子就可以写出代码,注意初始化的时候要将\(f[ \ ][ \ ]\)初始化为一个很小的负数,\(f[0][0]=0\)
\(Code:\)
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int ans=0;
char last=' ',ch=getchar();
while(ch>'9'||ch<'0') last=ch,ch=getchar();
while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
if(last=='-') ans=-ans;
return ans;
}const int mxt=5010;
int T,MaxP,w;
int Ap[mxt],Bp[mxt],As[mxt],Bs[mxt];
int f[mxt][mxt];
int main() {
T=read();
MaxP=read();
w=read();
for(int i=1;i<=T;i++) {
Ap[i]=read();
Bp[i]=read();
As[i]=read();
Bs[i]=read();
}
memset(f,0x9f,sizeof(f));
f[0][0]=0;
for(int i=1;i<=T;i++) {
for(int j=0;j<=MaxP;j++) {
f[i][j]=f[i-1][j];
if(i-w-1>=0) {
for(int k=max(0,j-As[i]);k<j;k++)
f[i][j]=max(f[i][j],f[i-w-1][k]-Ap[i]*(j-k));
for(int k=j+1;k<=min(MaxP,j+Bs[i]);k++) {
f[i][j]=max(f[i][j],f[i-w-1][k]+Bp[i]*(k-j));
}
}
if(j<=As[i])
f[i][j]=max(f[i][j],-Ap[i]*j);
printf("%d ",f[i][j]);
}
puts("");
}
printf("%d",f[T][0]);
return 0;
}
但不要以为这样就可以愉快的\(\mathfrak{AC}\)这道题,它毕竟是一道省选题\(\color{white}{(虽然年代已经很久远了}\)
实际复杂度\(O(T*MaxP^2)\),在\(T\)和\(MaxP\)都是\(2000\)的数量级的数据下,显然是过不去的(不要妄想跑过\(8e9\)
因此我们需要优化
看数据范围\(2000\)大致可以猜测是一个\(O(n^2)\)的代码
观察第\(3、4\)个式子,暴力拆解得到:
\(f[i][j]=Max\{f[i-w-1][k]-Ap[i]*j+Ap[i]*k\}\)
\(f[i][j]=Max\{f[i-w-1][k]-Bp[i]*j+Bp[i]*k\}\)
显然\(-Bp[i]*j\)与\(-Ap[i]*j\)的值不影响我们取最大值,因此我们可以提出来:
\(f[i][j]=Max\{f[i-w-1][k]+Ap[i]*k\}-Ap[i]*j\)
\(f[i][j]=Max\{f[i-w-1][k]+Bp[i]*k\}-Bp[i]*j\)
这两个式子像什么?像极了单调队列优化!
所以采用单调队列优化我们的第\(3、4\)个式子,就可以做到\(O(n^2)\)完成这道题(胜利的曙光\(\color{GOld}{!!!}\)
h=1;t=0;
for(int j=0;j<=MaxP;j++) {//购买股票,从小往大更新
while(h<=t&&q[h]<j-As[i])
//清除队首中不符合"第i天的一次买入至多只能购买AS_i股"的
h++;
while(h<=t&&cost1(i,q[t])<=cost1(i,j))
//如果队尾的收入<=当前的收入,弹出队尾(从前往后更新,i要大于q[t],如果队尾的收入<=当前的收入,显然i相比于q[t]一定更优)
t--;
q[++t]=j;
if(h<=t) //队列中有元素
f[i][j]=max(f[i][j],cost1(i,q[h])-Ap[i]*j);
}
h=1;t=0;
for(int j=MaxP;j>=0;j--) {//卖出股票,从大往小更新:由4式知,j位置的状态是从一个>j的位置转移而来的,因此倒序更新
while(h<=t&&q[h]>j+Bs[i])
h++;
while(h<=t&&cost2(i,q[t])<=cost2(i,j))
t--;
q[++t]=j;
if(h<=t)
f[i][j]=max(f[i][j],cost2(i,q[h])-Bp[i]*j);
}
\(Code:\)
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int ans=0;
char last=' ',ch=getchar();
while(ch>'9'||ch<'0') last=ch,ch=getchar();
while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar();
if(last=='-') ans=-ans;
return ans;
}const int mxt=5010;
int T,MaxP,w;
int Ap[mxt],Bp[mxt],As[mxt],Bs[mxt];
int f[mxt][mxt];
int q[mxt];
int h,t;
int cost1(int i,int j) {
return f[i-w-1][j]+Ap[i]*j;
}
int cost2(int i,int j) {
return f[i-w-1][j]+Bp[i]*j;
}
int main() {
T=read();
MaxP=read();
w=read();
for(int i=1;i<=T;i++) {
Ap[i]=read();
Bp[i]=read();
As[i]=read();
Bs[i]=read();
}
memset(f,0x9f,sizeof(f));
f[0][0]=0;
for(int i=1;i<=T;i++) {
for(int j=0;j<=MaxP;j++) {
f[i][j]=f[i-1][j];
if(j<=As[i])
f[i][j]=max(f[i][j],-Ap[i]*j);
}
if(i-w<=0) continue;
h=1;t=0;
for(int j=0;j<=MaxP;j++) {
while(h<=t&&q[h]<j-As[i]) h++;
while(h<=t&&cost1(i,q[t])<=cost1(i,j)) t--;
q[++t]=j;
if(h<=t)
f[i][j]=max(f[i][j],cost1(i,q[h])-Ap[i]*j);
}
h=1;t=0;
for(int j=MaxP;j>=0;j--) {
while(h<=t&&q[h]>j+Bs[i]) h++;
while(h<=t&&cost2(i,q[t])<=cost2(i,j)) t--;
q[++t]=j;
if(h<=t)
f[i][j]=max(f[i][j],cost2(i,q[h])-Bp[i]*j);
}
}
printf("%d",f[T][0]);
return 0;
}
Luogu P2569 [SCOI2010] 股票交易的更多相关文章
- [luogu] P2569 [SCOI2010]股票交易 (单调队列优化)
P2569 [SCOI2010]股票交易 题目描述 最近 \(\text{lxhgww}\) 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,\(\te ...
- LUOGU P2569 [SCOI2010]股票交易(单调队列优化dp)
传送门 解题思路 不难想一个\(O(n^3)\)的\(dp\),设\(f_{i,j}\)表示第\(i\)天,手上有\(j\)股的最大收益,因为这个\(dp\)具有单调性,所以\(f_i\)可以贪心的直 ...
- 洛谷P2569 [SCOI2010]股票交易
P2569 [SCOI2010]股票交易 题目描述 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股 ...
- P2569 [SCOI2010]股票交易 dp 单调队列优化
LINK:股票交易 题目确实不算难 但是坑点挺多 关于初值的处理问题我就wa了两次. 所以来谢罪. 由于在手中的邮票的数量存在限制 且每次买入卖出也有限制. 必然要多开一维来存每天的邮票数量. 那么容 ...
- P2569 [SCOI2010]股票交易
最近 \(lxhgww\) 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,\(lxhgww\) 预测到了未来 \(T\) 天内某只股票的走势,第 \( ...
- 洛谷 P2569[SCOI2010]股票交易(动规+单调队列)
//只能写出裸的动规,为什么会有人能想到用单调队列优化Orz 题目描述 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测 ...
- Luogu 2569 [SCOI2010]股票交易 (朴素动规转移 + 单调队列优化)
题意: 已知未来 N 天的股票走势,第 i 天最多买进 as [ i ] 股每股 ap [ i ] 元,最多卖出 bs [ i ] 股每股 bp [ i ] 元,且每天最多拥有 Mp 股,且每两次交易 ...
- 洛谷P2569 [SCOI2010]股票交易(单调队列)
传送门 惭愧……这种题目都没看出来…… 首先,我们用$dp[i][j]$表示在第$i$天,手上有$j$股时的最大收益 第一,我们可以直接买股票,即$dp[i][j]=-j*AP_i$,这个直接计算即可 ...
- 单调队列优化DP || [SCOI2010]股票交易 || BZOJ 1855 || Luogu P2569
题面:P2569 [SCOI2010]股票交易 题解: F[i][j]表示前i天,目前手中有j股的最大收入Case 1:第i天是第一次购买股票F[i][j]=-j*AP[i]; (1<=j< ...
随机推荐
- NOI2007 项链工厂
题目链接:戳我 60pts 有一点容易写错的小细节: 比如说求全局的段数的时候,如果只有一种颜色,那么当左右端点相等时,就不要ans--了. 注意右端点小于左端点的情况. #include<io ...
- 7.9模拟赛T1图的遍历(dfs)
图的遍历(dfs) [题目描述] 对于一个有向图G来说,我们存在一个经典的遍历算法,就是DFS (深度优先搜索遍历).将G以1号点为起点进行DFS后,我们可以 得到G的一棵DFS遍历树T.就此,我们可 ...
- [CSP-S模拟测试]:Drink(模拟)
题目传送门(内部题10) 输入格式 输入第一行三个数$N,M,Q$分别表示棋盘的行数.列数和操作个数.接下来$N$行每行$M$个数表示一开始棋盘上宝物的价值.接下来$Q$行每行$3$个数$x,y,c$ ...
- JDBC之——原理和连接数据库
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口 ...
- Nginx事件管理之epoll模块
1. epoll 原理 假设有 100 万用户同时与一个进程保持着 TCP 连接,而每一时刻只有几十个或几百个 TCP 连接时活跃的(接收到 TCP 包),也就是说,在每一时刻,进程只需要处理这 10 ...
- LeetCode 199. 二叉树的右视图(Binary Tree Right Side View)
题目描述 给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值. 示例: 输入: [1,2,3,null,5,null,4] 输出: [1, 3, 4] 解释: 1 ...
- Laravel5.2中Eloquent与DB类的区别是什么?
要了解这些先看看关于数据库组件的那些事儿(就是 Eloquent ORM) 数据库组件大概分了三层: 数据库连接层 查询构造层 应用层 来看一下每一层有哪些东西,分别对应文档的哪一部分: 数据库连接层 ...
- java 获取本地 mac 地址
主要参考:Java获取本机MAC地址/IP地址/主机名 做的更改: 1.我的windows是中文版,程序中获取mac时是按照physical address 获取的,添加上"物理地址&quo ...
- 如何查看 SELinux状态及关闭SELinux
查看SELinux状态: 1./usr/sbin/sestatus -v ##如果SELinux status参数为enabled即为开启状态 SELinux status: ...
- ModuleNotFoundError: No module named '_sqlite3'的解决办法:pipenv的用法
export PIPENV_VENV_IN_PROJECT=1pipenv --venvpipenv --where pipenv install -r requirements.txtpipenv ...