• 【HDU3401】Trade-单调队列优化DP


    测试地址:Trade

    题目大意:给定连续T天的股市情况,包含四个参数api,bpi,asi,bsi,表示第i天买价为api一股,卖价为bpi一股,当天最多能买asi股,最多能卖bsi股,一天之内只能在买和卖中选择一个,另外限制任何一天手中股票不能超过maxp股,如果在一天进行了交易(买或卖),那么接下来W天都不能交易。一开始有无限的本金,但是没有股票,求最后最多能赚多少钱。

    做法:每一天的操作无非就是三种:不交易,买,卖。按照这个写出状态转移方程,设dp[i][j]为第i天结束后手中持有j股的最大收益,则:

    dp[i][j]=max(dp[i-1][j],max(dp[x][k]-api*(j-k))(x≤i-w-1,k<j),max(dp[x][k]+bpi*(k-j))(x≤i-w-1,k>j));

    初始化:dp[0][0]=0,dp[i][j]=-inf(i≠0且j≠0)。

    注意到如果枚举x和k的话,这是一个O(T*maxp)的式子,那么总的复杂度将达到O(T^2*maxp^2),华丽爆炸。我们考虑枚举x的必要性,发现我们每次求dp[i][j]都要考察dp[i-1][j]的情况,也就是说dp[i][j]≥dp[i-1][j],所以在k相等的情况下,dp[x][k]在x取最大值时最大,所以x总是i-w-1,复杂度降低到O(T*maxp^2),仍然不能通过此题。再单独观察买和卖的式子,发现都能化成max(w[k])+c(l≤k≤r)的形式,对于买的式子,其中w[k]=dp[i-w-1][k]+api*k,c=-api*j,l=j-asi,r=j-1,卖的式子同理,我们发现在i和j相同的情况下,w[k]是由k唯一确定的变量(且可以O(1)算出),c是一个常数,且k的取值范围大小始终都是一个常数,这启示我们使用单调队列进行优化,于是复杂度降低到O(T*maxp),完美解决该题。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define inf 2000000000
    using namespace std;
    int tt,T,maxp,w,api[2010],bpi[2010],asi[2010],bsi[2010];
    int dp[2010][2010],h,t,q[2010];
    
    int main()
    {
      scanf("%d",&tt);
      while(tt--)
      {
        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;
    	dp[0][0]=0;
    	for(int i=1;i<=T;i++)
    	{
    	  int s=max(0,i-w-1);
    	  h=1,t=0;
    	  for(int j=0;j<=maxp;j++)
    	  {
    	    dp[i][j]=max(dp[i][j],dp[i-1][j]);
    		if (j>0)
    		{
    		  while(h<=t&&q[h]<j-asi[i]) h++;
    		  while(h<=t&&dp[s][j-1]+api[i]*(j-1)>=dp[s][q[t]]+api[i]*q[t]) t--;
    	      q[++t]=j-1;
    		  dp[i][j]=max(dp[i][j],dp[s][q[h]]-api[i]*(j-q[h]));
    		}
    	  }
    	  h=1,t=0;
    	  for(int j=maxp;j>=0;j--)
    	  {
    	    if (j<maxp)
    		{
    		  while(h<=t&&q[h]>j+bsi[i]) h++;
    		  while(h<=t&&dp[s][j+1]+bpi[i]*(j+1)>=dp[s][q[t]]+bpi[i]*q[t]) t--;
    	      q[++t]=j+1;
    		  dp[i][j]=max(dp[i][j],dp[s][q[h]]+bpi[i]*(q[h]-j));
    		}
    	  }
    	}
        
    	int ans=0;
    	for(int i=0;i<=maxp;i++)
    	  ans=max(ans,dp[T][i]);
    	printf("%d
    ",ans);
      }
      
      return 0;
    }
    


  • 相关阅读:
    nio/mina(三) mina传对象
    Android系统中长按事件的实现机制解析
    android游戏寻路算法
    Xcode 常用快捷键及代码自动排版
    java 日期加天数得到新的日期
    cygwin 中文乱码问题
    Android 中自定义手势
    mina服务端与c++客户端通信1
    java NIO 和阻塞I/O的区别
    Android读写文件
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793745.html
Copyright © 2020-2023  润新知