HDU 3401 Trade(斜率优化dp)

http://acm.hdu.edu.cn/showproblem.php?pid=3401

题意:
有一个股市,现在有T天让你炒股,在第i天,买进股票的价格为APi,卖出股票的价格为BPi,同时最多买进股票的数量为ASi,卖出股票的数量为BSi。一次交易之后要隔W天之后才能再次交易,并且手上最多持股maxP,问最多可以炒到多少钱。

思路:

首先列一个DP方程:

分别代表不买不卖,买进股票,卖出股票三种情况(上面 (j-k)<=AS[i] , (k-j)<=BS[i])。

那么这里需要枚举r和k的情况,由于相邻两次交易必须隔W天,也就是如果第i天交易了,那么至少要到第i+w+1天才能再次交易。如果我们在第i天要交易股票,那么前w天都是不买不卖的情况,那么前w天的情况都是一样的,所以这以r直接为i-w-1即可。

最后是将上面的式子化简一下:

可以看见右边是与k有关的表达式,左边是与j有关的表达式,右边我们只需要选择最大的值即可,那么这就可以用单调队列来优化了。

以买股票为例子说明:

因为是买股票,所以j肯定是大于k的,所以j从小到大枚举。每次计算出右边的值,单调队列保存递减值。每次取队首的最大值,当然队首元素必须满足AS[i]的条件,不满足就出队列。

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 const int maxn = 2000+5;
 5
 6 int t, maxp, w, ap[maxn], bp[maxn], as[maxn], bs[maxn], head, tail;
 7 int dp[maxn][maxn];
 8 struct node
 9 {
10     int p;
11     int x;
12 }q[maxn];
13
14 int main()
15 {
16     //freopen("in.txt","r",stdin);
17     int T;
18     scanf("%d",&T);
19     while(T--)
20     {
21         scanf("%d%d%d",&t,&maxp,&w);
22         for(int i=1;i<=t;i++)
23             scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]);
24
25         for(int i=0;i<=t;i++)
26             for(int j=0;j<=maxp;j++)
27                 dp[i][j] = -0x3f3f3f3f;
28
29         for(int i=1;i<=w+1;i++)
30             for(int j=0;j<=as[i];j++)
31                 dp[i][j] = -j*ap[i];
32
33         for(int i=2;i<=t;i++)
34         {
35             for(int j=0;j<=maxp;j++)
36                 dp[i][j] = max(dp[i][j],dp[i-1][j]);
37             if(i<=w+1)  continue;
38             //买进
39             head = tail = 1;
40             for(int j=0;j<=maxp;j++)
41             {
42                 int x = dp[i-w-1][j]+j*ap[i];
43                 while(head<tail && q[tail-1].x<x)  tail--;
44                 q[tail].x = x;
45                 q[tail++].p = j;
46                 while(head<tail && j-q[head].p>as[i]) head++;
47                 dp[i][j] = max(dp[i][j], q[head].x-j*ap[i]);
48             }
49
50             //卖出
51             head = tail = 1;
52             for(int j=maxp;j>=0;j--)
53             {
54                 int x = dp[i-w-1][j]+j*bp[i];
55                 while(head<tail && q[tail-1].x<x)  tail--;
56                 q[tail].x = x;
57                 q[tail++].p = j;
58                 while(head<tail && j+bs[i]<q[head].p) head++;
59                 dp[i][j] = max(dp[i][j], q[head].x-j*bp[i]);
60             }
61         }
62         int ans = 0;
63         for(int i=0;i<=maxp;i++)
64             ans = max(ans,dp[t][i]);
65         printf("%d\n",ans);
66     }
67     return 0;
68 }

原文地址:https://www.cnblogs.com/zyb993963526/p/8455300.html

时间: 2024-09-30 18:38:57

HDU 3401 Trade(斜率优化dp)的相关文章

Print Article hdu 3507 一道斜率优化DP 表示是基础题,但对我来说很难

Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 4990    Accepted Submission(s): 1509 Problem Description Zero has an old printer that doesn't work well sometimes. As it is antique

HDU 2829 Lawrence (斜率优化DP或四边形不等式优化DP)

题意:给定 n 个数,要你将其分成m + 1组,要求每组数必须是连续的而且要求得到的价值最小.一组数的价值定义为该组内任意两个数乘积之和,如果某组中仅有一个数,那么该组数的价值为0. 析:DP状态方程很容易想出来,dp[i][j] 表示前 j 个数分成 i 组.但是复杂度是三次方的,肯定会超时,就要对其进行优化. 有两种方式,一种是斜率对其进行优化,是一个很简单的斜率优化 dp[i][j] = min{dp[i-1][k] - w[k] + sum[k]*sum[k] - sum[k]*sum[

hdu 3401 单调队列优化+dp

http://acm.hdu.edu.cn/showproblem.php?pid=3401 Trade Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5188    Accepted Submission(s): 1776 Problem Description Recently, lxhgww is addicted to stoc

hdu 3401(单调队列优化dp)

注意:这题题意是有操作的天数相隔要大于w 然后列出状态转移方程就可以发现,可以用优点队列优化啦. 构造状态dp[i][j]表示第i 天拥有 j只股票的时候,赚了多少钱 状态转移有: 1.从前一天不买不卖: dp[i][j]=max(dp[i-1][j],dp[i][j]) 2.从前i-W-1天买进一些股: dp[i][j]=max(dp[i-W-1][k]-(j-k)*AP[i],dp[i][j]) 3.从i-W-1天卖掉一些股: dp[i][j]=max(dp[i-W-1][k]+(k-j)*

HDU 6619 Horse 斜率优化dp

http://acm.hdu.edu.cn/showproblem.php?pid=6619 #include<bits/stdc++.h> #define fi first #define se second #define INF 0x3f3f3f3f #define LNF 0x3f3f3f3f3f3f3f3f #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define pqueue priority_qu

hdu 2993 MAX Average Problem (斜率优化dp入门)

MAX Average Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5855    Accepted Submission(s): 1456 Problem Description Consider a simple sequence which only contains positive integers as

斜率优化dp简讲 &amp;&amp; HDU 3507 Print Article

Problem Description Zero has an old printer that doesn't work well sometimes. As it is antique, he still like to use it to print articles. But it is too old to work for a long time and it will certainly wear and tear, so Zero use a cost to evaluate t

HDU 3507 Print Article(斜率优化DP)

题目链接 题意 : 一篇文章有n个单词,如果每行打印k个单词,那这行的花费是,问你怎么安排能够得到最小花费,输出最小花费. 思路 : 一开始想的简单了以为是背包,后来才知道是斜率优化DP,然后看了网上的资料,看得还挺懂的,不过我觉得如果以后真遇到斜率DP,要推起来肯定不简单..... 网上资料1 网上资料2 1 #include <iostream> 2 #include <stdio.h> 3 4 using namespace std; 5 6 int q[500005],dp

HDU - 3401 Trade

题意:让你炒股票,每天都有买进的额度和价格以及卖出的额度和价格,并规定时间和最多的持有股票是多少,而且买卖操作要隔w+1天求最高的利润 思路:显然分三种情况:不买不卖,买,卖,设dp[i][j]表示第i天持有j股票的最高利润 如果不买不卖的话就是:dp[i][j]=dp[i-1][j] 买: dp[i][j]=max(dp[i][j],dp[pre][k]-(j-k)*ap[i]) 卖: dp[i][i]=max(dp[i][j],dp[pre][k]+(k-j)*bp[i]) 拿买来说的话:d

斜率优化DP总结

前言: 也是好久没有写题解了,最近主要学习了单调栈单调队列以及斜率优化DP这几个知识点,对于较难的斜率优化DP,做个小小的总结吧. 正(che)文(dan): T1 hdu 3507 在一个风和日丽的早上,你打开了网页,点进了hdu,偶然间看到了这道题,不屑的以为这仅仅是一个很水的DP,2分钟给出DP方程式,很快的写完后发现n的范围居然是500000,这让已经推出来的 O(n2)复杂度的递推式情何以堪,所以就产生了一种高逼格的优化方式:斜率优化. 这道题的方程式是什么呢? dp[i]=min(d