luogu P2569 [SCOI2010]股票交易 单调优化dp

参考:https://www.luogu.com.cn/blog/Sooke/solution-p2569

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=2001;
int n,m,w;
int ap,bp,as,bs;
int ans;
int f[N][N] ;// f[i][j] 表示第 i 天后拥有 j 张股票赚的最多钱数
int hh,tt,q[2001];
int main()
{
	cin>>n>>m>>w;
	memset(f,128,sizeof f); // 128 实际上给 f 数组赋的是 -inf,可以试试看
	for(int i=1;i<=n;i++)
	{
		//买入价格,卖出价格,最多买,最多卖
		cin>>ap>>bp>>as>>bs;
		for(int j=0;j<=as;j++)
			f[i][j]=-1*j*ap; //凭空买
		for(int j=0;j<=m;j++)
			f[i][j]=max(f[i][j],f[i-1][j]); // 不买也不卖
		if(i<=w)//如果小于天数,就不能卖
			continue; // 因为第 3,4 种情况都有 i - w - 1,如果 i <= w,会出现负下标
		//在之前的基础上买
		hh=1,tt=1; // 单调队列准备
		for(int j=0;j<=m;j++)
		{
			while(hh<tt&&q[hh]<j-as)
				hh++;
			while(hh<tt&&f[i-w-1][q[tt-1]]+q[tt-1]*ap<=f[i-w-1][j]+j*ap)
				tt--;
			q[tt++]=j;
			if(hh<tt)
				f[i][j]=max(f[i][j],f[i-w-1][q[hh]]+q[hh]*ap-j*ap);
		}
		//在之前的基础上卖
		hh=1,tt=1;
		for(int j=m;j>=0;j--)
		{
			while(hh<tt&&q[hh]>j+bs)
				hh++;
			while(hh<tt&&f[i-w-1][q[tt-1]]+q[tt-1]*bp<=f[i-w-1][j]+j*bp)
				tt--;
			q[tt++]=j;
			if(hh<tt)
				f[i][j]=max(f[i][j],f[i-w-1][q[hh]]+q[hh]*bp-j*bp);
		}
	}
	for(int i=0;i<=m;i++)
		ans=max(ans,f[n][i]);
	cout<<ans<<endl;
	return 0;
}
原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12916135.html