题目传送门https://www.luogu.org/problemnew/show/P2569

第一眼看题就觉得是个dp ,然后看到2000的范围,hmm大概是个n^2的2维dp

开始设状态,第一维肯定是天数的枚举,第二维...看着MaxP的范围,觉得应该是持有股票数量的枚举

那么dp[i][j]就是对于1~i天,第i天持有j张股票的情况下最多能赚的钱

然后想转移方程,分成几种情况

case 1:前面都不买,从第i天开始买

  也就是从一无所有的情况下买j张股票dp[i][j]=-APi*j

case 2:不买不卖

  这种情况下不会就不会受到W的限制,直接dp[i][j]=dp[i-1][j]

case 3:发生买卖

  首先要考虑应该从前面哪一天的状态转移过来,也就是上一次买卖在哪一天发生。

  乍一看好像没办法知道应该从哪一天转移,莫非又多一层1~i-W-1的循环?

  其实不用。上一次买卖所获得的最大值可以根据case 2的dp方程向后转移

  所以直接从i-W-1天转移就行

  case 3.1:又卖又买

    仔细想想,这种情况不可能成为最大值。因为有APi>=BPi,卖了又买不如买少点,多折腾是不行的

  case 3.2:只买不卖

    既然是买,那么之前持有的股票必然比j少,枚举之前持有的股票k,花钱(j-k)*APi

    dp[i][j]=dp[i-W-1][k]-(j-k)*APi;

  case3.3:只卖不买

    与case 3.2类似

    dp[i][j]=max dp[i-W-1][k]+(k-j)*BPi

大概就是这样。dp[T][0]就是最终答案(保险起见我写的是max dp[T][0~MaxP])

时间大概是O(n*MaxP^2)

预期50pt做法(实际70pt)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std; int T,MaxP,W; struct pig {
int APi,BPi,ASi,BSi;
} day[]; int dp[][]; int main() {
cin>>T>>MaxP>>W;
for(int i=; i<=T; i++) {
scanf("%d%d%d%d",&day[i].APi,&day[i].BPi,&day[i].ASi,&day[i].BSi);
}
for(int i=; i<=T; i++) {
for(int j=; j<=MaxP; j++) {
dp[i][j]=-;
}
}
dp[][]=; for(int i=;i<=T;i++){
for(int j=;j<=MaxP;j++){
dp[i][j]=dp[i-][j];
if(j<=day[i].ASi){ dp[i][j]=max(dp[i][j],-j*day[i].APi);
}
if(i-W-<){
continue;
}
for(int k=j-day[i].ASi;k<j;k++){
if(k<){
continue;
}
dp[i][j]=max(dp[i][j],dp[i-W-][k]-(j-k)*day[i].APi);
}
for(int k=j+;k<=j+day[i].BSi;k++){
if(k>MaxP){
break;
}
dp[i][j]=max(dp[i][j],dp[i-W-][k]+(k-j)*day[i].BPi);
}
}
}
int ans=;
for(int j=; j<=MaxP; j++) {
ans=max(ans,dp[T][j]);
}
cout<<ans;
return ;
}
/*
输入
初始化 赋-inf,dp[0][0]=0
dp循环
i 天数1-T
j 当前持股数0-Maxp
从当前天开买 j<=Asi dp[i][j]=-j*APi;
不买不卖 dp[i][j]=dp[i-1][j]
如果i-W-1>=0
k 前次购买时持股数 买股 (j-Asi)~j&&>=0
dp[i][j]=max dp[i-W-1][k]-(j-k)*APi;
k 前次购买时持股数 卖股 j~(j+Bsi)&&<=MaxP
dp[i][j]=max dp[i-W-1][k]+(k-j)*BPi
输出,max(dp[0][0~MaxP]) 自测数据
2 1
1 1 1
1 1 1
2 1 1
3 1 1
4 1 1 2 0
1 1 1
1 1 1
2 1 1
3 1 1
4 1 1
*/

(附伪代码提纲)


怎么继续优化呢?

如果仍然保持dp[i][j]的形式,i和j的循环肯定是不能去掉的,所以考虑优化k

用case 3.2:只买不卖 举例

它的dp方程是dp[i][j]=max dp[i-W-1][k]-(j-k)*APi;

乘法分配律得dp[i][j]=max dp[i-W-1][k]+k*APi-j*APi;

j是枚举出来的,所以可以拆分一下max,得dp[i][j]=max(dp[i-W-1][k]+k*APi)-j*APi;

因为对于每个确定的i和j,k属于区间 [j - ASi ,j-1] ,假设i是定值,ASi就是定值。那么对于所有j,k的区间大小是一样的

一个长度固定的区间一格一格的移动...这不就是滑动窗口

单调队列优化,O(n*MaxP),100pt到手

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std; int T,MaxP,W; struct MonoQue {
int lim;//维持的长度
int size;//最大存储量
int que[];//单调队列
int data[];//维护的数据
int head,tail; void init(int mys,int mylim) {
size=mys;
lim=mylim;
head=;
tail=;
}
void push(int id) {//向单调队列中加入并维护,id可以在特殊情况下跳跃前进
if(id<=size) {//防越界处理
for(; head<tail;) {
if(data[que[tail-]]>data[id]) {
break;
}
tail--;
}
que[tail]=id;
tail++;
}
if(que[head]+lim<=id) {
pop();
}
}
void pop() {
head++;
}
int quetop() {
return que[head];
}
int top() {
return data[quetop()];
}
}; struct pig {
int APi,BPi,ASi,BSi;
} day[]; int dp[][]; int main() {
cin>>T>>MaxP>>W;
for(int i=; i<=T; i++) {
scanf("%d%d%d%d",&day[i].APi,&day[i].BPi,&day[i].ASi,&day[i].BSi);
}
for(int i=; i<=T; i++) {
for(int j=; j<=MaxP; j++) {
dp[i][j]=-;
}
}
dp[][]=; MonoQue buy,sell;
for(int i=; i<=T; i++) {
buy.init(MaxP,day[i].ASi+);
sell.init(MaxP,day[i].BSi+);
if(i-W->=) {//防数组超下界
for(int j=; j<=MaxP; j++) {
buy.data[j]=dp[i-W-][j]+j*day[i].APi;
sell.data[j]=dp[i-W-][j]+j*day[i].BPi;
}
}
for(int j=; j<day[i].BSi; j++) {
sell.push(j);//sell需要预先加入
}
for(int j=; j<=MaxP; j++) {
dp[i][j]=dp[i-][j]; if(j<=day[i].ASi) {
dp[i][j]=max(dp[i][j],-j*day[i].APi);
}
if(i-W-<) {
continue;
}
buy.push(j);
dp[i][j]=max(dp[i][j],buy.top()-j*day[i].APi); sell.push(j+day[i].BSi);//单调队列里会处理超了MaxP的情况 dp[i][j]=max(dp[i][j],sell.top()-j*day[i].BPi);
}
}
int ans=;
for(int j=; j<=MaxP; j++) {
ans=max(ans,dp[T][j]);
}
cout<<ans;
return ;
}
/*
自测数据
3 2 0
2 1 1 1
3 2 1 1
4 3 1 1
*/

参考:

https://www.luogu.org/blog/Sooke/solution-p2569

洛谷P2569 股票交易的更多相关文章

  1. 洛谷P2569 股票交易 [SCOI2010] dp

    正解:dp+单调队列优化 解题报告: 先放个传送门鸭qwq umm首先dp转移挺好想的?就买和不买 f[i][j]表示第i天手上有j的股份的最多钱,转移也很好想?就枚举第1天到第i-w-1天枚举买k股 ...

  2. 洛谷P2569 股票交易【dp】【单调队列】

    题目描述 最近 \text{lxhgww}lxhgww 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,\text{lxhgww}lxhgww 预测到了 ...

  3. 洛谷P2569 [SCOI2010]股票交易

    P2569 [SCOI2010]股票交易 题目描述 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股 ...

  4. 洛谷 P2569[SCOI2010]股票交易(动规+单调队列)

    //只能写出裸的动规,为什么会有人能想到用单调队列优化Orz 题目描述 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测 ...

  5. 洛谷P2569 [SCOI2010]股票交易(单调队列)

    传送门 惭愧……这种题目都没看出来…… 首先,我们用$dp[i][j]$表示在第$i$天,手上有$j$股时的最大收益 第一,我们可以直接买股票,即$dp[i][j]=-j*AP_i$,这个直接计算即可 ...

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

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

  7. 洛谷 [SCOI2010]股票交易 | 单调性DP

    题目链接 #include<cstdio> #include<algorithm> #include<cstring> #define N 2005 using n ...

  8. BZOJ1855或洛谷2569 [SCOI2010]股票交易

    一道单调队列优化\(DP\) BZOJ原题链接 洛谷原题链接 朴素的\(DP\)方程并不难想. 定义\(f[i][j]\)表示到第\(i\)天,手上持有\(j\)股时的最大收益. 转移方程可以分成四个 ...

  9. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

随机推荐

  1. MyBatis mysal 日报表,月,年报表的统计

    mysql 按日.周.月.年统计sql语句整理,实现报表统计可视化 原文地址:http://blog.csdn.net/u010543785/article/details/52354957 最近在做 ...

  2. js中的原型

    一:原型属性 函数本身也是一个包含了方法和属性的对象. 定义一个函数foo(),访问其他对象一样访问该函数的属性: function foo(a, b) { return a * b; } foo.l ...

  3. 加密算法之非对称加密RSA

    一:非对称加密的由来 RSA公钥加密算法是1977年由Ron Rivest.Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的.RSA取名来自开发他们三者的名字.RSA是目前最有 ...

  4. Linux发布WebApi

    一:WebApi 使用Owin来做  http://www.cnblogs.com/xiaoyaodijun/category/666029.html 二:安装最新版的Jexus服务 https:// ...

  5. python-中缀表达式转前缀表达式

    作完了中缀前缀,作一个归纳吧. https://www.cnblogs.com/unixfy/p/3344550.html # coding = utf-8 class Stack: def __in ...

  6. AspNetCore MVC + Vue.Js 项目搭建

    1.准备 全文重点在于搭建环境,其他相关知识点请百度. VS2017 升级到最新的版本 安装 net core 2.0 安装 npm (npm相关使用请百度或咨询前端小伙伴) 全局安装 webpack ...

  7. Java线程池参数

    关于Java线程池的参数设置.线程池是Java多线程里开发里的重要内容,使用难度不大,但如何用好就要明白参数的含义和如何去设置.干货里的内容大多是参考别人的,加入了一些知识点的扩充和看法.希望能对多线 ...

  8. C# 之 反射性能优化3

    阅读目录 开始 用Delegate优化反射的缺点 用Delegate优化反射的优点 用CodeDOM优化反射的优点 如何用好CodeDOM? 用CodeDOM优化反射的缺点 能不能不使用委托? 根据反 ...

  9. 【Android】Android 代码判断当前设备是否为模拟器

    [Android]Android 代码判断当前设备是否为模拟器 方法比较简单,直接粘贴代码 //判断当前设备是否是模拟器.如果返回TRUE,则当前是模拟器,不是返回FALSE public stati ...

  10. net core体系-web应用程序-4net core2.0大白话带你入门-8asp.net core 内置DI容器(DependencyInjection,控制翻转)的一点小理解

    asp.net core 内置DI容器的一点小理解   DI容器本质上是一个工厂,负责提供向它请求的类型的实例. .net core内置了一个轻量级的DI容器,方便开发人员面向接口编程和依赖倒置(IO ...