hdu3401 Trade(单调队列优化dp)

Trade

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4734    Accepted Submission(s):
1587

Problem Description

Recently, lxhgww is addicted to stock, he finds some
regular patterns after a few days‘ study.
He forecasts the next T days‘ stock
market. On the i‘th day, you can buy one stock with the price APi or sell one
stock to get BPi.
There are some other limits, one can buy at most ASi
stocks on the i‘th day and at most sell BSi stocks.
Two trading days should
have a interval of more than W days. That is to say, suppose you traded (any buy
or sell stocks is regarded as a trade)on the i‘th day, the next trading day must
be on the (i+W+1)th day or later.
What‘s more, one can own no more than MaxP
stocks at any time.

Before the first day, lxhgww already has infinitely
money but no stocks, of course he wants to earn as much money as possible from
the stock market. So the question comes, how much at most can he earn?

Input

The first line is an integer t, the case number.
The
first line of each case are three integers T , MaxP , W .
(0 <= W < T
<= 2000, 1 <= MaxP <= 2000) .
The next T lines each has four
integers APi,BPi,ASi,BSi( 1<=BPi<=APi<=1000,1<=ASi,BSi<=MaxP),
which are mentioned above.

Output

The most money lxhgww can earn.

Sample Input

1
5 2 0
2 1 1 1
2 1 1 1
3 2 1 1
4 3 1 1
5 4 1 1

Sample Output

3

Author

lxhgww

Source

HDOJ
Monthly Contest – 2010.05.01

Recommend

lcy   |   We have carefully selected several similar
problems for you:  3400 3403 3404 3402 3415

Statistic | Submit | Discuss | Note

Home | Top Hangzhou
Dianzi University Online Judge 3.0
Copyright © 2005-2017 HDU ACM Team. All Rights Reserved.
Designer & Developer: Wang
Rongtao
 LinLe GaoJie GanLu
Total
0.000000(s) query 4, Server time : 2017-02-02 18:39:06, Gzip enabled
Administration

 题目大意:知道之后n天的股票买卖价格(api,bpi),以及每天股票买卖数量上限(asi,bsi),问他最多能赚多少钱。开始时有无限本金,要求任两次交易需要间隔W天以上,即第i天交易,第i+w+1天才能再交易。同时他任意时刻最多只能拥有maxp的股票,

/*
1. dp[i][j] 表示前 i 天手里有 j 支股票时所获得的最大收益,因为要间隔 w+1 天才能进行一次买卖
所以前 w+1 天只能进行一个操作,那就是买操作。
2. 关于赋初值问题,合法的状态也有可能为负值的,而且结果要取最大值
所以非法状态要赋值为 -INFS.
3. dp[i][j] = max(dp[i-w-1][x] - (j-x)*AP, dp[i-w-1][y] + (y-j)*BP);
 另外还有第 i 天什么都不做的情况此时为 dp[i][j] = max(dp[i][j], dp[i-1][j]).
4. 关于转移方程,时间复杂度是很高的,所以要采取单调队列优化
deq[],pos[] 分别放置窗口里面的最大值以及最大值所在的窗口位置。
这里用了一个结构体的队列直接维护这两个信息
5. 如何构造单调队列里面的转移,其实很简单例如 dp[3] = max(dp[1] + 2 * v, dp[2] + 1 * v);
两边同时减去 3 * v 就可以变成一个通项公式了,偏移正好。高中数学知识。
6.推到队列优化也可以这样做,只考虑买的情况,卖的和它对称。
dp[i][j] = max(dp[i-w-1][k]-j*ap[i]+k*ap[i]),移下项变成dp[i][j]+j*ap[i]=max(dp[i-w-1][k]+k*ap[i]),
很明显可以把后面维护成一个递减的单调队列,每次取队首元素,使得复杂度降为O(N*P)
*/
#include<cstdio>
#include<cstring>
#define MAX 2005
#define inf 0xfffff
#define max(a,b) ((a)>(b)?(a):(b))

using namespace std;
int T,MaxP,W;
int APi[MAX],BPi[MAX],ASi[MAX],BSi[MAX];
int dp[MAX][MAX];//dp[i][j]第i天持有j股的最大值
//dp[i][j]=max{dp[i-1][j],max{dp[r][k]-APi[i]*(j-k)}(0<r<i-w,k<j),max{dp[r][k]+BPi[i]*(k-j)}(0<r<i-w,k>j)}
struct node
{
    int x;//存dp[i-w-1][k]+APi[i]*k或dp[i-w-1][k]+BPi[i]*k
    int p;//当前持股数
} q[2005],temp;
int front,back;
int main()
{
    int cas;
    scanf("%d",&cas);
    for(; cas--;)
    {
        scanf("%d%d%d",&T,&MaxP,&W);
        for(int i=1; i<=T; ++i)
            scanf("%d%d%d%d",APi+i,BPi+i,ASi+i,BSi+i);
        for(int i=0; i<=T; ++i)
            for(int j=0; j<=MaxP; ++j)
                dp[i][j]=-inf;
        for(int i=1; i<=W+1; ++i)
            for(int j=0; j<=ASi[i]; ++j)
                dp[i][j]=(-APi[i]*j);
        for(int i=2; i<=T; ++i)
        {
            for(int j=0; j<=MaxP; ++j)
                dp[i][j]=max(dp[i][j],dp[i-1][j]);
            if(i<=W+1) continue;
            //买入
            front=back=1;
            for(int j=0; j<=MaxP; ++j)
            {
                temp.p=j;
                temp.x=dp[i-W-1][j]+APi[i]*j;
                for(;front<back&&q[back-1].x<temp.x;--back);
                q[back++]=temp;
                for(;front<back&&q[front].p+ASi[i]<j;++front);
                dp[i][j]=max(dp[i][j],q[front].x-APi[i]*j);
            }
            //卖出
            front=back=1;
            for(int j=MaxP; j>=0; --j)
            {
                temp.p=j;
                temp.x=dp[i-W-1][j]+BPi[i]*j;
                for(;front<back&&q[back-1].x<temp.x;--back);
                q[back++]=temp;
                for(;front<back&&q[front].p-BSi[i]>j;++front);
                dp[i][j]=max(dp[i][j],q[front].x-BPi[i]*j);
            }
        }
        int ans=0;
        for(int i=0;i<=MaxP;++i)
            ans=max(ans,dp[T][i]);
        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-12-24 19:29:21

hdu3401 Trade(单调队列优化dp)的相关文章

hdu3401:单调队列优化dp

第一个单调队列优化dp 写了半天,最后初始化搞错了还一直wa.. 题目大意: 炒股,总共 t 天,每天可以买入na[i]股,卖出nb[i]股,价钱分别为pa[i]和pb[i],最大同时拥有p股 且一次交易后至少要间隔w天才能再次交易,初始有0股,本金无限,求最大收益 题解:dp[i][j]表示第 i 天,有 j 股的最大收益 状态转移 dp[i][j]=max{dp[i-1][j](不买不卖),dp[r][k]-(j-k)*pa[i](i-r>w,j-k<=na[i],买),dp[r][k]+

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>=

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 单调队列维护的是前

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

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

【单调队列优化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

洛谷P1725 琪露诺 单调队列优化 DP

洛谷P1725 琪露诺 单调队列优化 DP 题意:1--n 每个点都有一个权值,从当前点i可以到达i+l--i+r 之间的点, 动态规划 方程 为 f[ i ] = max(f[ i ],f[ k ] ) +a[ i ] i-r<=k<=i-l 然而这样复杂度 就为 n^2 因为相当于 dp 是在求 一段区间的最大值,而这个最大值就可以用O(n) 来维护 注意 这个O(n) 是均摊O(n) 即将所有固定区间长度的 最大值求出来 是 O(n)的这样就把复杂度降到 O(n) 级别了 1 #incl

Parade(单调队列优化dp)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2490 Parade Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 902    Accepted Submission(s): 396 Problem Description Panagola, The Lord of city F lik