[SCOI2010]股票交易

题面描述

传送门

思路

这道题DP的很明显啊(可惜我就是不会写啊)

提前声明:

这里的 n n n T T T m m m M a x P MaxP MaxP t t t W W W a a a A P i AP_i APi c c c B P i BP_i BPi,b为 A S i AS_i ASi d d d B S i BS_i BSi

首先根据题意,因为 i i i天买了股票, i + t i+t i+t天也不能买股票,干脆 t + + t++ t++

状态转移方程:
F i , j = { F i − 1 , j − a ∗ j ( j ≤ b ) F i − t , k − a ∗ j + a ∗ k ( 0 ≤ k ≤ j − 1 & j − k ≤ b ) F i − t , k + c ∗ k − c ∗ j ( j + 1 ≤ k ≤ m & k − j ≤ d ) } F_{i,j}=\begin{Bmatrix} F_{i-1,j}\\ -a*j(j\le b)\\ F_{i-t, k}-a*j+a*k(0\le k\le j-1\And j-k\le b)\\ F_{i-t,k}+c*k-c*j(j+1\le k\le m\And k-j\le d)\end{Bmatrix} Fi,j=Fi1,jaj(jb)Fit,kaj+ak(0kj1&jkb)Fit,k+ckcj(j+1km&kjd)

第一条方程就是这天啥都不干(真是个有趣的家伙)。

第二条方程就是在前 b b b天买进 j j j张股票。

第三条方程就是在前 i − t i-t it天已经买了k张股票,在 i i i天再买 i − k i-k ik张股票。

第三条方程就是在前 i − t i-t it天买了k张股票,在 i i i天卖剩 j j j张股票。

这种 D P DP DP已经可以拿下 70 70 70分了,

然后呢?(就T的没边了)

在这里插入图片描述

观察许久,我发现貌似第 3 3 3 4 4 4个方程可以单调队列优化。
(因为它们具有单调性)

踢队头很好写,踢队尾可以观察发现有共性:

F i − t , k + c ( a ) ∗ k F_{i-t,k}+c(a)*k Fit,k+c(a)k

因此我们就可以以这个为标准,踢掉不优的队尾。

while(l<=r&&f[i-t][j]+a*j>=f[i-t][q[r]]+a*q[r])--r;
while(l<=r&&f[i-t][j]+c*j>=f[i-t][q[r]]+c*q[r])--r;

貌似这道题就结束了?

AC code

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define gc getchar()
using namespace std;
const int N=2010;
inline void qr(int &x)
{
	x=0;int f=1;char c=gc;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
	x*=f;
}
void qw(int x)
{
	if(x<0)x=-x,putchar('-');
	if(x/10)qw(x/10);
	putchar(x%10+48);
}
int f[N][N];
int q[N];
int main()
{
	int n,m,t;qr(n),qr(m),qr(t);t++;
	f[0][0]=-N*N;for(int j=1;j<=m+1;j++)f[0][j]=f[0][j-1];
	for(int i=1;i<=n;i++)
	{
		int a,b,c,d,l,r;
		qr(a),qr(c),qr(b),qr(d);
		for(int j=0;j<=m+1;j++)f[i][j]=f[i-1][j];
		for(int j=0;j<=b;j++)f[i][j]=max(f[i][j],-a*j);
		if(i>t)
		{
			l=1;r=0;q[1]=0;
			for(int j=0;j<=m;j++)
			{
				while(l<=r&&q[l]<j-b)++l;
				f[i][j]=max(f[i][j],f[i-t][q[l]]-a*j+a*q[l]);
				while(l<=r&&f[i-t][j]+a*j>=f[i-t][q[r]]+a*q[r])--r;
				q[++r]=j;
			}
			l=1;r=0;q[1]=m+1;
			for(int j=m;j>=0;j--)
			{
				while(l<=r&&q[l]-j>d)++l;
				f[i][j]=max(f[i][j],f[i-t][q[l]]+c*q[l]-c*j);
				while(l<=r&&f[i-t][j]+c*j>=f[i-t][q[r]]+c*q[r])--r;
				q[++r]=j;
			}
		}
	}
	qw(f[n][0]);puts("");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值