股票交易

我终于打传送门了
我们发现这道题长得非常像dp。但这不是简单的dp。(这不是废话吗 )我们发现这个dp的转移是不能单单用一个循环做(因为限制不同)。故我们分为4种情况讨论并分别dp。

我们先定义 d p [ i ] [ j ] dp[i][j] dp[i][j]为第i天手上有的股票数。

  1. 不买不卖  我们就从前一个状态上搞。 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i1][j]
  2. 只买不卖  这里发现其实这种情况也分为2种情况:
       <3>以前没有   d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , − i n [ i ] . p ∗ j ) dp[i][j]=max(dp[i][j],-in[i].p*j) dp[i][j]=max(dp[i][j],in[i].pj)
       <4>以前有   d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − w − 1 ] [ k ] − ( j − k ) ∗ i n [ i ] . p ) ( j − i n [ i ] . s < = k < = j ) dp[i][j]=max(dp[i][j],dp[i-w-1][k]-(j-k)*in[i].p)(j-in[i].s<=k<=j) dp[i][j]=max(dp[i][j],dp[iw1][k](jk)in[i].p)(jin[i].s<=k<=j)。我们由于1操作,只用让 i − w − 1 i-w-1 iw1来比较。
  3. 只卖不买   d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − w − 1 ] [ k ] + ( k − j ) ∗ o u t [ i ] . p ) ( j < = k < = j + o u t [ i ] . s ) dp[i][j]=max(dp[i][j],dp[i-w-1][k]+(k-j)*out[i].p)(j<=k<=j+out[i].s) dp[i][j]=max(dp[i][j],dp[iw1][k]+(kj)out[i].p)(j<=k<=j+out[i].s)

然后,就上马吧!(加了单调队列优化)

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N = 2002;
struct node {
	int p, s;
}in[N], out[N];
int n, limit, w, head, tail, dp[N][N], q[N];
int main() {
	memset(dp, -0x3f, sizeof dp);
	scanf("%d %d %d", &n, &limit, &w);
	for(int i = 1; i <= n; i ++) {//为什么四个搞在一个循环?前面的会对后面有影响,有些操作需要更新。
		scanf("%d %d %d %d", &in[i].p, &out[i].p, &in[i].s, &out[i].s);
		for(int j = 0; j <= limit; j ++)
			dp[i][j] = dp[i - 1][j];
		for(int j = 0; j <= in[i].s; j ++)
			dp[i][j] = max(dp[i][j], -in[i].p * j);
		if(i > w + 1) {//减出来1维至少是1
			head = 1;
			tail = 0;
			for(int j = limit; j >= 0; j --) {//这里因为k的取值要反着打
				for(; head <= tail && q[head] > j + out[i].s; head ++);
				for(; head <= tail && dp[i - w - 1][j] + j * out[i].p >= dp[i - w - 1][q[tail]] + q[tail] * out[i].p; tail --);
				q[++ tail] = j;//要先插入队列再做,可能队列没有值
				dp[i][j] = max(dp[i][j], dp[i - w - 1][q[head]] + q[head] * out[i].p - j * out[i].p);
			}
			head = 1;
			tail = 0;
			for(int j = 0; j <= limit; j ++) {
				for(; head <= tail && q[head] < j - in[i].s; head ++);
				for(; head <= tail && dp[i - w - 1][j] + j * in[i].p >= dp[i - w - 1][q[tail]] + q[tail] * in[i].p; tail --);
				q[++ tail] = j;
				dp[i][j] = max(dp[i][j], dp[i - w - 1][q[head]] + q[head] * in[i].p - j * in[i].p);
			}
		}
	}
	printf("%d\n", dp[n][0]);//此时代表第n天拥有0张股票,显然这是最优的
	return 0;
} 

如有问题,请在评论区指出,谢谢!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值