## Problem Description

Recently, lxhgww is addicted to stock, he finds some regular patterns after a few days’ study.
He forecasts the next T days’ stock market. On the i’th day, you can buy one stock with the price APi or sell one stock to get BPi.
There are some other limits, one can buy at most ASi stocks on the i’th day and at most sell BSi stocks.
Two trading days should have a interval of more than W days. That is to say, suppose you traded (any buy or sell stocks is regarded as a trade)on the i’th day, the next trading day must be on the (i+W+1)th day or later.
What’s more, one can own no more than MaxP stocks at any time.

Before the first day, lxhgww already has infinitely money but no stocks, of course he wants to earn as much money as possible from the stock market. So the question comes, how much at most can he earn?

## input

The first line is an integer t, the case number.
The first line of each case are three integers T , MaxP , W .
(0 <= W < T <= 2000, 1 <= MaxP <= 2000) .
The next T lines each has four integers APi，BPi，ASi，BSi( 1<=BPi<=APi<=1000,1<=ASi,BSi<=MaxP), which are mentioned above.

## output

The most money lxhgww can earn.

1
5 2 0
2 1 1 1
2 1 1 1
3 2 1 1
4 3 1 1
5 4 1 1

3

## 中文翻译

int maxn=-1;
for(int i=1;i<=maxp;i++){
maxn=max(maxn,dp[T][i]);
}

dp[i][j]=max(dp[i][j],dp[i-1][j]);

dp[i][j]=max(dp[i-W-1][k]-(j-k)*ap[i],dp[i][j]);
//这是买进(1<=k<j)
dp[i][j]=max(dp[i-W-1][k]+(k-j)*bp[i],dp[i][j]);
//这是卖出(j<k<maxp)

dp[i][j]=max(dp[i-W-1][k]-(j-k)*ap[i],dp[i][j]);
//这是买进(1<=k<j)
dp[i][j]=max(dp[i-W-1][k]+(k-j)*bp[i],dp[i][j]);
//这是卖出(j<k<maxp)

dp[i][j]其实是要与（dp[i-w-1][k]-j* ap[i]+k* ap[i]）在枚举完所有的k值之后取得的最大值比较最大值进行更新

scanf("%d%d%d",&T,&MAXP,&W);
//T表示T天,MAXP表示最多持有多少股票,W表示两次交易之间至少要间隔多少天;
for(int i=1;i<=T;i++)
scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]);
//ap表示买入价格,bp表示卖出价格,as表示最多买多少,bs表示最多卖多少;
for(int i=0;i<=T;i++) dp[i][j]=MINN;
for(int i=1;i<=T;i++) dp[i][0]=0;//不持股票至少盈利0元(从头到尾不买不卖)
for(int i=1;i<=W+1;i++)
for(int j=1;j<=as[i];j++)
dp[i][j]=-j*ap[i];//前W+1天只能买不能卖
for(int j=1;j<=MAXP;j++)//也可以不买不卖,这个时候拥有i张股票
for(int i=2;i<=W+1;i++)
d[i][j]=max(dp[i][j],dp[i-1][j]);
//从第2天开始枚举,与前一天的状态进行比较
//这里可能要理解一下,我举个例子,比如我在前一天买了同样数量的股票(因为我们是在比较j相同时的值)
//而我们只能在预处理的这W天买一次,而先买的可以先卖,所以先买的更便宜的永远是最优的
//然后开始进行初始化之后的W+2天到最后一天的dp转移,注意初始化非常重要,到现在初始化就处理完了
//这个初始化(dp[i][j]=max(dp[i][j],dp[i-1][j]);)也可以放在之后的循环里

for(int i=2;i<=T;i++){
for(int j=0;j<=MAXP;j++) dp[i][j]=Max(dp[i-1][j],dp[i][j]);
if(i<=W+1) continue;
for(int j=MAXP;j>=0;j--) modify_sale(i,j);
}

//这个时候的k就等于j,因为对于同一个i,j是从0一路枚举过来的
q[tail].value=dp[i-W-1][j]+ap[i]*j;
q[tail].number=j;
//此时insert了一个k==j时候的状态
tail++;
//如果我要达到的股票数减去我已经有的股票数大于了我最多能买的股票数
//维护了队列之后,队首的就是最大的值

modify_sale()函数

q[tail].value=dp[i-W-1][j]+bp[i]*j;
q[tail].number=j;
tail++;

for(int i=0;i<=MAXP;i++)
maxn=Max(maxn,dp[T][i]);
cout<<maxn<<endl;

#include<cstdio>
#include<cstring>
#include<iostream>
#define MINN -1e8
#define MAXN  12444
#define MAX 2000+10
using namespace std;

int Max(int x,int y){ return x>y?x:y; }
int Min(int x,int y){ return x>y?y:x; }
int as[MAX],bs[MAX],ap[MAX],bp[MAX];
int dp[MAX][MAX];
int W,t,T,MAXP,d;
struct Queue{
int value;
int number;
}q[MAX*2];

q[tail].value=dp[i-W-1][j]+ap[i]*j;
q[tail].number=j;
tail++;
}

void modify_sale(int i,int j){
q[tail].value=dp[i-W-1][j]+bp[i]*j;
q[tail].number=j;
tail++;
}

int main(){
scanf("%d",&t);
while(t--){
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]);
for(int i=0;i<=T;i++)
for(int j=0;j<=MAXP;j++) dp[i][j]=MINN;
for(int i=1;i<=T;i++) dp[i][0]=0;
for(int i=1;i<=W+1;i++)
for(int j=0;j<=as[i];j++) dp[i][j]=-j*ap[i];
dp[0][0]=0;
for(int i=2;i<=T;i++){
for(int j=0;j<=MAXP;j++) dp[i][j]=Max(dp[i-1][j],dp[i][j]);
if(i<=W+1) continue;
for(int j=MAXP;j>=0;j--) modify_sale(i,j);
}
int maxn=MINN;
for(int i=0;i<=MAXP;i++)
maxn=Max(maxn,dp[T][i]);
cout<<maxn<<endl;
}
return 0;
}

• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120