[SCOI2010]股票交易

題面描述

傳送門

思路

這道題DP的很明顯啊(可惜我就是不會寫啊)

提前聲明:

這裏的nnTTmmMaxPMaxPttWWaaAPiAP_iccBPiBP_i,b爲ASiAS_iddBSiBS_i

首先根據題意,因爲ii天買了股票,i+ti+t天也不能買股票,乾脆t++t++

狀態轉移方程:
Fi,j={Fi1,jaj(jb)Fit,kaj+ak(0kj1&jkb)Fit,k+ckcj(j+1km&kjd)}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}

第一條方程就是這天啥都不幹(真是個有趣的傢伙)。

第二條方程就是在前bb天買進jj張股票。

第三條方程就是在前iti-t天已經買了k張股票,在ii天再買iki-k張股票。

第三條方程就是在前iti-t天買了k張股票,在ii天賣剩jj張股票。

這種DPDP已經可以拿下7070分了,

然後呢?(就T的沒邊了)

在這裏插入圖片描述

觀察許久,我發現貌似第3344個方程可以單調隊列優化。
(因爲它們具有單調性)

踢隊頭很好寫,踢隊尾可以觀察發現有共性:

Fit,k+c(a)kF_{i-t,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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章