luogu P2569 [SCOI2010]股票交易

fxt275307894a發表於2020-10-07

題面傳送門
這道題暴力dp是很好想的。
就是分別從上一天,最晚可轉移的天,憑空買來轉移。
因為有狀態自然疊加所以只要轉移最晚可轉移的天就好了。
然後會發現這個是可以正反兩邊單調佇列優化的。
複雜度 O ( T P ) O(TP) O(TP)
程式碼實現:

#include<cstdio>
#include<cstring>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,w,x,y,z,f[2039][2039],q[2039],head,tail;
int a[2039],b[2039],c[2039],d[2039];
int main(){
//	freopen("1.in","r",stdin);
	register int i,j;
	scanf("%d%d%d",&n,&m,&w);
	for(i=1;i<=n;i++) scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
	memset(f,-0x3f,sizeof(f));
	for(i=1;i<=n;i++) f[i][0]=0;
	for(i=1;i<=n;i++){
		for(j=1;j<=c[i];j++) f[i][j]=-a[i]*j;
		for(j=0;j<=m;j++) f[i][j]=max(f[i][j],f[i-1][j]);
		if(i<=w+1) continue;
		head=tail=0;
		for(j=0;j<=m;j++){
			while(head!=tail&&q[head+1]+c[i]<j) head++;
			while(head!=tail&&f[i-w-1][q[tail]]-(j-q[tail])*a[i]<=f[i-w-1][j]) tail--;
			q[++tail]=j;
			f[i][j]=max(f[i][j],f[i-w-1][q[head+1]]-(j-q[head+1])*a[i]);
		}
		head=tail=0;
		for(j=m;j>=0;j--){
			while(head!=tail&&q[head+1]>j+d[i]) head++;
			while(head!=tail&&f[i-w-1][q[tail]]+(q[tail]-j)*b[i]<=f[i-w-1][j]) tail--;
			q[++tail]=j;
			f[i][j]=max(f[i][j],f[i-w-1][q[head+1]]+(q[head+1]-j)*b[i]);
		}
	}
	printf("%d\n",f[n][0]);
}

相關文章