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

题目链接

BZOJ1855

题解

设\(f[i][j]\)表示第\(i\)天结束时拥有\(j\)张股票时的最大收益

若\(i \le W\),显然在这之前不可能有交易

\[f[i][j] = max\{f[i - 1][j],-ap[i] * j\} \quad [j \le as[i]]\]

否则,就有三种选择:

①购买

\[f[i][j] = max\{f[i - W - 1][k] - ap[i] * (j - k)\} \quad[k \le j][j - k \le as[i]]\]

②卖出

\[f[i][j] = max\{f[i - W - 1][k] + bp[i] * (k - j)\} \quad[k \ge j][k - j \le bs[i]]\]

③什么也不做

\[f[i][j] = max\{f[i][j],f[i - 1][j]\}\]

其中③总共是\(O(n^2)\)的

①和②如果逐个枚举是\(O(n^3)\)的,无法承受

拆开式子可发现可以用单调队列优化成\(O(n^2)\)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define cls(s) memset(s,-0x3f3f3f3f,sizeof(s))
using namespace std;
const int maxn = 2005,maxm = 100005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
int f[maxn][maxn],T,P,W,ap[maxn],bp[maxn],as[maxn],bs[maxn];
struct node{
    int k,v;
}q[maxn];
int head,tail;
int main(){
    T = read(); P = read(); W = read();
    REP(i,T) ap[i] = read(),bp[i] = read(),as[i] = read(),bs[i] = read();
    cls(f); f[0][0] = 0; int ans = 0;
    for (int i = 1; i <= T; i++){
        for (int j = 0; j <= P; j++) f[i][j] = f[i - 1][j];
        if (i <= W){
            for (int j = 0; j <= as[i]; j++)
                f[i][j] = max(f[i][j],-ap[i] * j);
        }
        else {
            head = 0; tail = -1;
            for (int j = 0; j <= P; j++){
                while (head <= tail && (j - q[head].k) > as[i]) head++;
                while (head <= tail && q[tail].v < f[i - W - 1][j] + ap[i] * j) tail--;
                q[++tail] = (node){j,f[i - W - 1][j] + ap[i] * j};
                f[i][j] = max(f[i][j],q[head].v - ap[i] * j);
            }
            head = 0; tail = -1;
            for (int j = P; j >= 0; j--){
                while (head <= tail && (q[head].k - j) > bs[i]) head++;
                while (head <= tail && q[tail].v < f[i - W - 1][j] + bp[i] * j) tail--;
                q[++tail] = (node){j,f[i - W - 1][j] + bp[i] * j};
                f[i][j] = max(f[i][j],q[head].v - bp[i] * j);
            }
        }
        ans = max(ans,f[i][0]);
    }
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/9019607.html

时间: 2024-08-06 14:18:16

BZOJ1855 [Scoi2010]股票交易 【单调队列优化dp】的相关文章

bzoj1855: [Scoi2010]股票交易--单调队列优化DP

单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w-1][k]+k*Ap[i]的单调性即可 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 2010; 6 int

1855: [Scoi2010]股票交易[单调队列优化DP]

1855: [Scoi2010]股票交易 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1083  Solved: 519[Submit][Status][Discuss] Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=

BZOJ 1855 [Scoi2010]股票交易 单调队列优化DP

题意:链接 方法:单调队列优化DP 解析:噢又是一道情况很多的题,然而三种更新我又落下一种导致样例不过,后来看题解才恍然- -最SB的一种更新居然忘了. 状态好想f[i][j]代表前i天有j双袜子时的最大利润. 三种更新: 第一种:f[i][j]=max(f[i][j],f[i?1][j]):(然而我忘了这一种) 第二种:买入f[i][j]=max(f[i][j],f[i?w?1][k]?(j?k)?a[i].ap)(k>=j?a[i].as); 第三种:卖出f[i][j]=max(f[i][j

LUOGU P2569 [SCOI2010]股票交易(单调队列优化dp)

传送门 解题思路 不难想一个\(O(n^3)\)的\(dp\),设\(f_{i,j}\)表示第\(i\)天,手上有\(j\)股的最大收益,因为这个\(dp\)具有单调性,所以\(f_i\)可以贪心的直接从\(f_{i-w-1}\)那一层转移来,转移时枚举一下当前买卖多少.考虑优化,发现每次其实就是一个区间取\(max\),是由\(AS\)和\(BS\)所限制的区间,所以单调队列优化就好了,一个正着做一个倒着做,时间复杂度\(O(n^2)\) 代码 #include<bits/stdc++.h>

【bzoj1855||hdu3401】股票交易——单调队列优化dp

代码基本是跟着yy dalao码的吧, 主要是要知道单调队列优化要怎么做, f[i][j]表示第i天手里有j股时的收益. 从第一天到第w+1天初始化为-e[i].ap*j(因为此时只能买不能卖),其余为-inf. 分三种情况: 1.不买不卖:即f[i][j]=max(f[i][j],f[i-1][j]); 2.买进: f[i][j]=max(f[i-W-1][k]-(j-k)*e[i].ap,f[i][j]).在这里j-e[i].as<k<=mxa,利用f[i][j]=max(f[i-W-1]

AcWing - 332 - 股票交易 = 单调队列优化dp

https://www.acwing.com/problem/content/334/ 第一次写单调队列优化的dp,首先朴素的做法不难想到,就是复杂度 \(O(n^3)\) ,然后考虑优化. 每天都从 \(pre=max(0,i-w-1)\) 天转移过来就刚刚好了. 考虑每个k是怎么更新j的. 买入股票: \(dp[i][j]=max\{dp[pre][k]-(j-k)*AP_i\;|\;k \leq j\;and\;(j-k) \leq AS_i\}\) \(dp[i][j]=max\{dp[

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

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1855 题意:最近lxhgww又迷上了投资股票, 通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每 个i,都有APi>=BPi),但是每天不能无限制地交易,于是股票交易所规定第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BS

HDU 4122 Alice&#39;s mooncake shop 单调队列优化dp

Alice's mooncake shop Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4122 Description The Mid-Autumn Festival, also known as the Moon Festival or Zhongqiu Festival is a popular harvest festival celebrated by Ch

Tyvj1305最大子序和(单调队列优化dp)

描述 输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大. 例如 1,-3,5,1,-2,3 当m=4时,S=5+1-2+3=7当m=2或m=3时,S=5+1=6 输入格式 第一行两个数n,m第二行有n个数,要求在n个数找到最大子序和 输出格式 一个数,数出他们的最大子序和 测试样例1 输入 6 4 1 -3 5 1 -2 3 输出 7 备注 数据范围:100%满足n,m<=300000 是不超过m,不是选m个!!!!! /* 单调队列优化dp 单调队列维护的是前

【单调队列优化dp】uestc 594 我要长高

http://acm.uestc.edu.cn/#/problem/show/594 [AC] 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=5e4+2; 5 const int inf=0x3f3f3f3f; 6 int n,c; 7 int cur; 8 int dp[2][maxn]; 9 int q[maxn]; 10 int main() 11 { 1