luogu P2569 [SCOI2010]股票交易

背景:

清明节假期结束了…

题目传送门:

https://www.luogu.org/problemnew/show/P2569

题意:

假的模拟一个股票交易的过程(作弊)。
可以在某一天购买或卖出股票,单价为 A P i , B P i AP_i,BP_i APi,BPi;且限制了购买或卖出的数量 A S i , B S i AS_i,BS_i ASi,BSi;且两次交易的时间至少为 w w w天。
求最后能赚多少钱。

思路:

显然是 D P DP DP
f i , j f_{i,j} fi,j表示第 i i i天结束交易后持有 j j j股的最大利润。

则考虑 4 4 4种情况:
[ 1 ] : [1]: [1]:凭空买入股票(原来没买):
f i , j = − j ∗ A P i f_{i,j}=-j*AP_i fi,j=jAPi(其中 j ≤ A S i j≤AS_i jASi)。

[ 2 ] : [2]: [2]:又买入股票(原来买过):
假设原来持有 k k k股。
因为两次交易的时间至少为 w w w天,所以必须从 f i − w − 1 , k f_{i-w-1,k} fiw1,k转移过来。
f i , j = max ⁡ ( f i , j , f i − w − 1 , k − ( j − k ) ∗ A P i ) f_{i,j}=\max(f_{i,j},f_{i-w-1,k}-(j-k)*AP_i) fi,j=max(fi,j,fiw1,k(jk)APi)(其中 k &gt; 0 , 0 &lt; j − k ≤ A S i k&gt;0,0&lt;j-k≤AS_i k>0,0<jkASi得到 k ∈ [ j − A S i , j ) k∈[j-AS_i,j) k[jASi,j))。

[ 3 ] : [3]: [3]:不操作
f i , j = max ⁡ ( f i , j , f i − 1 , j ) f_{i,j}=\max(f_{i,j},f_{i-1,j}) fi,j=max(fi,j,fi1,j)

[ 4 ] : [4]: [4]:卖出股票(原来必须持有)
假设原来持有 k k k股。
因为两次交易的时间至少为 w w w天,所以必须从 f i − w − 1 , k f_{i-w-1,k} fiw1,k转移过来。
f i , j = max ⁡ ( f i , j , f i − w − 1 , k + ( k − j ) ∗ B P i ) f_{i,j}=\max(f_{i,j},f_{i-w-1,k}+(k-j)*BP_i) fi,j=max(fi,j,fiw1,k+(kj)BPi)(其中 k &gt; 0 , 0 &lt; k − j ≤ B S i k&gt;0,0&lt;k-j≤BS_i k>0,0<kjBSi得到 k ∈ ( j , j + B S i ] k∈(j,j+BS_i] k(j,j+BSi])。

此时时间复杂度为 Θ ( n 3 ) \Theta(n^3) Θ(n3)
怎么优化?
发现 [ 2 ] [ 4 ] [2][4] [2][4]情况太慢,考虑优化这两个。

先考虑 [ 2 ] [2] [2]情况。
f i , j = max ⁡ ( f i , j , f i − w − 1 , k − ( j − k ) ∗ A P i ) f_{i,j}=\max(f_{i,j},f_{i-w-1,k}-(j-k)*AP_i) fi,j=max(fi,j,fiw1,k(jk)APi)(其中 k ∈ [ j − A S i , j ) k∈[j-AS_i,j) k[jASi,j)
拆括号,得到: f i , j = max ⁡ ( f i , j , f i − w − 1 , k − j ∗ A P i + k ∗ A P i ) f_{i,j}=\max(f_{i,j},f_{i-w-1,k}-j*AP_i+k*AP_i) fi,j=max(fi,j,fiw1,kjAPi+kAPi)
稍微移一下项,得到: f i , j = max ⁡ ( f i , j , f i − w − 1 , k + k ∗ A P i − j ∗ A P i ) f_{i,j}=\max(f_{i,j},f_{i-w-1,k}+k*AP_i-j*AP_i) fi,j=max(fi,j,fiw1,k+kAPijAPi)
在枚举 i , j i,j i,j时, ( − j ∗ A P i ) (-j*AP_i) (jAPi)就是定值了,所以我们要使得 ( f i − w − 1 , k + k ∗ A P i ) (f_{i-w-1,k}+k*AP_i) (fiw1,k+kAPi)尽可能大,单调队列优化即可。

[ 4 ] [4] [4]情况同理。

O K OK OK了。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
	int n,m,w;
	int f[2010][2010],que[2010];
int main()
{
	int ap,bp,as,bs;
	scanf("%d %d %d",&n,&m,&w);
	memset(f,-63,sizeof(f));
	for(int i=1;i<=n;i++)
	{
		scanf("%d %d %d %d",&ap,&bp,&as,&bs);
		for(int j=0;j<=as;j++)
			f[i][j]=-j*ap;
		for(int j=0;j<=m;j++)
			f[i][j]=max(f[i][j],f[i-1][j]);
		if(i<=w) continue;
		int head=1,tail=0;
		for(int j=0;j<=m;j++)
		{
			while(head<=tail&&que[head]<j-as) head++;
			if(head<=tail) f[i][j]=max(f[i][j],f[i-w-1][que[head]]-(j-que[head])*ap);
			while(head<=tail&&f[i-w-1][que[tail]]+que[tail]*ap<=f[i-w-1][j]+j*ap)
				tail--;
			que[++tail]=j;
		}
		head=1,tail=0;
		for(int j=m;j>=0;j--)
		{
			while(head<=tail&&que[head]>j+bs) head++;
			if(head<=tail) f[i][j]=max(f[i][j],f[i-w-1][que[head]]+(que[head]-j)*bp);
			while(head<=tail&&f[i-w-1][que[tail]]+que[tail]*bp<=f[i-w-1][j]+j*bp)
				tail--;
			que[++tail]=j;
		}
	}
	printf("%d",f[n][0]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值