zoukankan      html  css  js  c++  java
  • ●BZOJ 1855 [Scoi2010]股票交易

    题链:

    http://www.lydsy.com/JudgeOnline/problem.php?id=1855

    题解:

    DP,单调队列优化。
    (好久没做 DP题,居然还意外地想出来了)


    定义 dp[i][k] 表示前 i天,手上还有 k股的最大收益。
    (注意这个定义是个前缀的形式)
    假设枚举到了第 i天,令 j=i-W-1。
    那么dp[i][]就由dp[j][]转移而来。(说了是前缀形式的啦,就不要去枚举 j-1,j-2...了)
    转移还是比较显然的:
    枚举第 i 天结束手上还剩的股数 k:
          枚举今日购买 d张:cmax(dp[i][k],dp[j][k-d]-d*AP);
          枚举今日卖出 d张:cmax(dp[i][k],dp[j][k+d]+d*BP);
          然后再来一个前缀的转移:cmax(dp[i][k],dp[i-1][k]);
    这个复杂度是 T*MAXP*MAXP的,只能过 50分。

    考虑优化(以购买转移为例),
    显然转移的区间为连续的一段,
    即若对于 dp[i][k]来说,转移来源是 dp[j][k-1]~dp[j][k-AS]。
    且不难发现,如果 k-1>=x>y>=k-AS,且 dp[j][x] > dp[j][y]-val  (val=(x-y)*AP),
    那么如论如何dp[j][y]都不可能贡献答案。

    所以就用单调队列维护每次转移的最值就好啦。
    一个小技巧:在从 计算 dp[i][k] 到 计算 dp[i][k+1] 时,
    显然单调队列里的旧元素的贡献相比刚刚加进队列的 newval=dp[j][k]来说都会减一个 AP,
    但不好整体修改,(难道你想用数据结构维护?)
    所以就令新加进队列的值 newval=dp[j][k]+k*AP
    保持好队列里的元素的相对大小关系就好了(即dp[j][k-1]始终比dp[j][k]多减了一个AP)。

    (卖出的转移就类似了。)
    最终复杂度可以做到 T*MAXP

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define MAXN 2005
    #define ll long long
    #define filein(x) freopen(#x".in","r",stdin);
    #define fileout(x) freopen(#x".out","w",stdout);
    using namespace std;
    ll dp[MAXN][MAXN],qv[MAXN],ANS,newval;
    int T,MAXP,W,AP,BP,AS,BS,qk[MAXN];
    void cmax(ll &a,ll b){
    	if(a<b) a=b;
    }
    int main()
    {
    	filein(trade); fileout(trade);
    	memset(dp,0xcc,sizeof(dp)); dp[0][0]=0;
    	scanf("%d%d%d",&T,&MAXP,&W);
    	for(int i=1,j,l,r;i<=T;i++){ //2000
    		scanf("%d%d%d%d",&AP,&BP,&AS,&BS);
    		j=max(i-W-1,0);
    		for(int k=0;k<=MAXP;k++)//50->2000 //前缀形式,今日不做任何操作 
    			cmax(dp[i][k],dp[i-1][k]);
    		l=1;r=1; qk[l]=0; qv[l]=dp[j][0];
    		for(int k=1;k<=MAXP;k++){//50->2000
    			//购置 
    			//for(int d=1;d<=AS&&k-d>=0;d++) cmax(dp[i][k],dp[j][k-d]-1ll*d*AP);
    			while(l<=r&&k-qk[l]>AS) l++;
    			cmax(dp[i][k],dp[j][qk[l]]-1ll*(k-qk[l])*AP);
    			newval=dp[j][k]+1ll*k*AP;
    			while(l<=r&&qv[r]<=newval) r--; 
    			r++; qk[r]=k; qv[r]=newval;			
    		}
    		l=1;r=1; qk[l]=MAXP; qv[l]=dp[j][MAXP];
    		for(int k=MAXP-1;k>=0;k--){//50->2000
    			//出售 
    			//for(int d=1;d<=BS&&k+d<=MAXP;d++) cmax(dp[i][k],dp[j][k+d]+1ll*d*BP);
    			while(l<=r&&qk[l]-k>BS) l++;
    			cmax(dp[i][k],dp[j][qk[l]]+1ll*(qk[l]-k)*BP);
    			newval=dp[j][k]-1ll*(MAXP-k)*BP;
    			while(l<=r&&qv[r]<=newval) r--; 
    			r++; qk[r]=k; qv[r]=newval;			
    		}
    	} 
    	//for(int k=0;k<=MAXP;k++) cmax(ANS,dp[T][k]);
    	cout<<dp[T][0];
    	return 0;
    }
    

  • 相关阅读:
    POJ2376 Cleaning Shifts
    百度首页图标
    NOIP2016换教室
    CH3803扑克牌
    【POJ2723】Get Luffy Out
    【USACO13DEC】 最优挤奶
    【SP2916】Can you answer these queries V
    【线段树】各种模板集合
    【SCOI2013】摩托车交易
    【CF1174D】 Ehab and the Expected XOR Problem
  • 原文地址:https://www.cnblogs.com/zj75211/p/8005145.html
Copyright © 2011-2022 走看看