洛谷P2569 dp + 单调队列优化

题目传送门

题意:

初始时你没有股票。

第 \dpi{150}i 天股票购买单价 ap_i ,卖出单价是 bp_i 。

第 \dpi{150}i 天最多购买 as_i 个股票,最多卖出 bs_i 个股票。

你持有股票个数在任何时刻不能超过 maxp 个。

买股票或卖股票都称为交易。

假如第 \dpi{150}i 天你进行了交易,那么下次最早交易时间是第 i+w+1 天。即两次交易至少间隔 w 天。

问你 T 天后,你最多拥有多少钱。

数据范围:0 \leqslant w < T \leqslant 2000 ,1\leqslant maxp\leqslant 2000 。

1 \leqslant bp_i\leqslant ap_i\leqslant 1000 ,1\leqslant as_i,bs_i \leqslant maxp 。

题解:

这个应该能想到是dp。

dp[i][j] 表示第 i 天结束时你有 j 个股票时拥有的最大钱数。

分四种情况讨论:

(1)第 i 天凭空买股票,就是前 i-1 天不进行交易,第 i 天你买股票。

dp[i][j] = max(dp[i][j] , -ap[i] * j)

(2)第 i 天不进行交易。

dp[i][j] = max(dp[i][j] , dp[i - 1][j])

(3)前面进行过交易,第 i 天买股票。

dp[i][j] = max(dp[i][j] , dp[i - w - 1][k] + (k - j) * ap[i])

其中 k 是有范围的,max(0,j - as[i]) <= k <= j - 1 。

(4)前面进行过交易,第 i 天卖股票。

dp[i][j] = max(dp[i][j] , dp[i - w - 1][k] + (k - j) * bp[i])

其中 k 是有范围的,j + 1 <= k <= min(maxp , j + bs[i]) 。

直接暴力计算时间复杂度是 O(T*maxp*maxp) ,接受不了。

所以要优化。考虑单调队列优化。

每次计算第 i 天的状态时,我们维护第 i-w-1 的状态的单调队列,在所需范围内寻找最大值即可。

单调队列优化后时间复杂度是 O(T*maxp) ,可以接受。

感受:

代码:

#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
typedef pair<int , int> pii ;
const int maxn = 2005 ;
int t , maxp , w ;
int ap , bp , as , bs ;
int dp[maxn][maxn] ;
int q[maxn] ;
//deque<int> q ;
int main()
{
	scanf("%d%d%d" , &t , &maxp , &w) ;
	for(int i = 0 ; i <= t ; i ++)
	  for(int j = 0 ; j <= maxp ; j ++)
	    dp[i][j] = -2e9 ;
	dp[0][0] = 0 ;
	for(int i = 1 ; i <= t ; i ++)
	{
		scanf("%d%d%d%d" , &ap , &bp , &as , &bs) ;
		//凭空买
		for(int j = 0 ; j <= as ; j ++)
		  dp[i][j] = -ap * j ;
		//不买也不卖
		for(int j = 0 ; j <= maxp ; j ++)
		  dp[i][j] = max(dp[i][j] , dp[i - 1][j]) ; 
		if(i - w - 1 < 1)  continue ;
		int l = 1 , r = 0;
        for(int j = 0 ; j <= maxp ; j++)
		{
            while(l <= r && q[l] < j - as)
                l++;
            while(l <= r && 
			dp[i - w - 1][q[r]] + q[r] * ap 
			<= 
			dp[i - w - 1][j] + j * ap)
                r--;
            q[++r] = j; 
            if(l <= r)
                dp[i][j] = max(dp[i][j] , dp[i - w - 1][q[l]] + 
				q[l] * ap - j * ap); 
        }
        l = 1 , r = 0;
        for(int j = maxp ; j >= 0 ; j--){
            while(l <= r && q[l] > j + bs)
                l++; 
            while(l <= r && dp[i - w - 1][q[r]] + q[r] * bp <= 
			dp[i - w - 1][j] + j * bp)
                r--; 
            q[++r] = j; 
            if(l <= r)
                dp[i][j] = max(dp[i][j] , dp[i - w - 1][q[l]] + 
				q[l] * bp - j * bp); 
        }
	}
	int ans = 0 ;
	for(int i = 0 ; i <= maxp ; i ++)  ans = max(ans , dp[t][i]) ;
	printf("%d\n" , ans) ;
	return 0 ;
}
发布了215 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Irving0323/article/details/104227240
今日推荐