hdu 3401 Trade 单调队列优化dp

28 篇文章 0 订阅

hdu 3401 Trade

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

题意:已知未来n天股市的形式、最多可持股量maxp、最少隔w天可操作,以及每天买进价格bp、卖出价格sp、最多可买进数量bn、最多可卖出数量sn

求最大收益

/*
    dp[i][j]= MAX(dp[i][j], dp[i-1][j]); //不动
    dp[i][j]= MAX(dp[i][j], MAX(dp[i-w-1][k] + k*sp[i]) - j*sp[i]); //卖
    // 0<= (k-j)<= sn[i]
    dp[i][j]= MAX(dp[i][j], MAX(dp[i-w-1][k] + k*bp[i]) - j*bp[i]); //买
    // 0<= (j-k)<= bn[i]
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn= 2010;
int bp[maxn], sp[maxn], sn[maxn], bn[maxn], maxp, w, n, dp[maxn][maxn];
struct node{
    int pos, val;
}que[maxn];
int MAX(int x, int y){
    return x>y?x:y;
}
int MIN(int x, int y){
    return x<y?x:y;
}
void dynamic(){
    int i, j, k, head, tail, s, pre;
    node tmp;
    memset( dp, 0xcf, sizeof( dp));
    for( i=1; i<= n; i++){
        for( j= 0; j<=MIN(maxp, bn[i]); j++){
            dp[i][j]= -bp[i]*j;
        }
    }
    for( i= 2; i<= n; i++){
        for( j= 0; j<=maxp; j++){
            dp[i][j]= MAX(dp[i][j], dp[i-1][j]);
        }
    }
    for( i= w+2; i<=n; i++){
       // k= 0;                         //buy
        pre= i- w - 1;
        head=0; tail= -1;
	/*
        对于买的情况
        dp[i][j]= MAX(dp[i][j], MAX(dp[i-w-1][k] + k*bp[i]) - j*bp[i]);    
        0<= (j-k)<= bn[i]
        pre天的股票数<= i天的数量,故k只需枚举到最大i天目前所看的最大数量,即j 故处理买的情况j应从0~maxp更新,用单调队列维护 
        */ 
        for( j= 0; j<= maxp; j++){
            dp[i][j]= MAX(dp[i][j], dp[i-1][j]);
            tmp.val= dp[pre][j] + j*bp[i];
            tmp.pos= j;
            while( head <= tail && que[tail].val < tmp.val) tail--;
            que[++tail]= tmp;
            while( head <= tail && (j- que[head].pos ) > bn[i]) head++;
            if( head <= tail) dp[i][j]= MAX( dp[i][j], que[head].val - j*bp[i] );
           // cout<<"a"<<i<<"  "<<j<<"  "<<dp[i][j]<<endl;
        }
        head= 0; tail= -1;       //sell
        for( j= maxp; j>= 0; j--){
            dp[i][j]= MAX(dp[i][j], dp[i-1][j]);
            tmp.val= dp[pre][j] + j*sp[i];
            tmp.pos= j;
            while( head <= tail && que[tail].val < tmp.val) tail--;
            que[++tail]= tmp;
            while( head <= tail && ( que[head].pos - j) > sn[i]) head++;
            if( head <= tail) dp[i][j]= MAX( dp[i][j], que[head].val - j*sp[i]);
           // cout<<i<<"  "<<j<<"  "<<dp[i][j]<<endl;
        }
    }
}
int main(){
  //  freopen("1.txt", "r", stdin);
    int i, j, k, T, mm;
    scanf("%d", &T);
    while( T--){
        scanf("%d%d%d", &n, &maxp, &w);
        for( i=1; i<=n; i++){
            scanf("%d%d%d%d", &bp[i], &sp[i], &bn[i], &sn[i]);
        }
        dynamic();
        mm= 0;
        for( i=0 ; i<=maxp; i++ ){
            mm= MAX(mm, dp[n][i]);
        }
        printf("%d\n", mm);
    }
    return 0;
}




























评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值