YY_More

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

看到这道题之后设计出的状态是f[i,j]为第i天各种交易之后持有j股票的情况下所能获得的最大利益。

那么转移应该是f[i,j]=f[i',j']+(j'-j)*x[i]

其中i-i'>W,当j'>j时,j'-j<=BS[i],x[i]=BP[i]。当j>j'时,j-j'<=AS[i],x[i]=AP[i]

这样的复杂度是T^2*MaxP^2

我们观察到,对于i和i+1,其决策域基本上是重复的,于是将f[i,j]的状态改为前i天各种交易之后持有j股票的情况下所能获得的最大利益。

这样f[i,j]=max(f[i-1,j],f[i-W-1,j']+(j'-j)*x[i]),但是T*MaxP^2还是要超时

我们把买和卖的决策分开考虑,以便得到进一步的优化

以买入为例,f[i,j]=max(f[i-W-1,j']+(j'-j)*AP[i])=max(f[i-W-1,j']+j'*AP[i])-j*AP[i],符合单调队列优化的模型,优化后的总时间复杂度为T*MaxP

要注意初始化

//By YY_More
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int f[2012][2012],D[2012];
int t,T,MaxP,W,L,R,AP[2012],BP[2012],AS[2012],BS[2012];
void initer(){
	fill(&f[0][0],&f[W+1][MaxP]+1,-2100000000);
	for (int k=1;k<W+2;k++){
		for (int j=0;j<=AS[k];j++)
			f[k][j]=max(-AP[k]*j,f[k-1][j]);
		for (int j=AS[k]+1;j<=MaxP;j++)
			f[k][j]=f[k-1][j];
	}	
};		
void init(int x){
	for (int j=0;j<=MaxP;j++)
		f[x][j]=f[x-1][j];
};	
void buy(int x){
	L=0;R=-1;
	for (int j=0;j<=MaxP;j++){
		while (L<=R&&f[x-W-1][D[R]]+D[R]*AP[x]<=f[x-W-1][j]+j*AP[x]) R--;
		D[++R]=j;
		while (j-D[L]>AS[x]) L++;
		f[x][j]=max(f[x][j],f[x-W-1][D[L]]-(j-D[L])*AP[x]);
	}
};
void sell(int x){
	L=0;R=-1;
	for (int j=MaxP;j>=0;j--){
		while (L<=R&&f[x-W-1][D[R]]+D[R]*BP[x]<=f[x-W-1][j]+j*BP[x]) R--;
		D[++R]=j;
		while (D[L]-j>BS[x]) L++;
		f[x][j]=max(f[x][j],f[x-W-1][D[L]]+(D[L]-j)*BP[x]);
	}
};	
int main(){
	scanf("%d",&t);
	while (t-->0){
		scanf("%d%d%d",&T,&MaxP,&W);
		for (int i=1;i<=T;i++)
			scanf("%d%d%d%d",&AP[i],&BP[i],&AS[i],&BS[i]);
		initer();
		for (int i=W+2;i<=T;i++){
			init(i);
			sell(i);
			buy(i);
		}
		printf("%d\n",f[T][0]);
	}
	return 0;
}
posted on 2011-06-23 14:36  YY_More  阅读(187)  评论(0编辑  收藏  举报