Trade
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3588 Accepted Submission(s): 1161
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?
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.
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#define maxn 2015
using namespace std;
int ap[maxn],bp[maxn],as[maxn],bs[maxn];
int dp[maxn][maxn];
int n,maxp,W,ans;
int main()
{
int t;
scanf("%d",&t);
while(t--){
memset(dp,0,sizeof(dp));
ans=0;
scanf("%d %d %d",&n,&maxp,&W);
for(int i=1;i<=n;i+=1){
scanf("%d %d %d %d",&ap[i],&bp[i],&as[i],&bs[i]);
}
for(int i=1;i<=maxp;i+=1){
dp[1][i]=dp[1][i-1]-ap[i];
}
for(int i=2;i<=n;i+=1){
for(int j=0;j<=maxp;j+=1){
dp[i][j]=max(dp[i-1][0]-j*ap[i],dp[i-1][j]);
if(i>W+1){
//dp[i][j]=max(dp[i-1][0]-j*ap[i],dp[i-1][j]);
for(int k=1;k<=j&&k<=as[i];k+=1){ /*買進*/
//for(int k=1;j+k<=maxp&&k<=as[i];k+=1){
dp[i][j]=max(dp[i][j],dp[i-W-1][j-k]-ap[i]*k);
//dp[i][j]=max(dp[i][j],dp[i-W-1][j+k]-ap[i]*k);
}
for(int k=1;j+k<=maxp&&k<=bs[i];k+=1){ /*賣出*/
//for(int k=1;k<=j&&k<=bs[i];k+=1){
dp[i][j]=max(dp[i][j],dp[i-W-1][j+k]+bp[i]*k);
//dp[i][j]=max(dp[i][j],dp[i-W-1][j-k]+bp[i]*k);
}
}
//else{
//dp[i][j]=dp[i-1][j];
//dp[i][j]=max(dp[i-1][j],dp[i-1][0]-j*ap[i]);
//}
if(i==n){
ans=max(ans,dp[i][j]);
}
}
}
printf("%d\n",/*dp[n][0]*/ans);
}
return 0;
}
第二遍,用單調隊列優化,wa了很多,但最後過了(下面是註釋版和簡明版兩個版本):
<pre name="code" class="cpp">#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#define maxn 2052
using namespace std;
int ap[maxn],bp[maxn],as[maxn],bs[maxn];
int dp[maxn][maxn];
int q[maxn],J[maxn];
int n,maxp,W,ans;
int main()
{
int t;
scanf("%d",&t);
while(t--){
memset(dp,128,sizeof(dp));
//原來錯了,因爲沒有初始化無窮小,這裏也導致了8到3的蛻變
//想想在i=n-1的某種情況下,從q裏取出的值暫時是負的,
//如果初始化爲0這個時候就就不會選擇負的數了
ans=0;
scanf("%d %d %d",&n,&maxp,&W);
for(int i=1;i<=n;i+=1){
scanf("%d %d %d %d",&ap[i],&bp[i],&as[i],&bs[i]);
}
/*dp[1][0]=0;
for(int i=1;i<=maxp;i+=1){
dp[1][i]=dp[1][i-1]-ap[1];
}*/
dp[0][0]=0;
for(int i=1;i<=W+1;i+=1){
for(int j=0;j<=maxp&&j<=as[i];j+=1){ //因爲是前W+1天只能買一次,所以必須加上一個j<=as[i]的限制
dp[i][j]=-j*ap[i];
}
}
for(int i=1;i<=n;i+=1){
for(int j=0;/*i>=W+2&&*/j<=maxp;j+=1){
//這裏不能有註釋掉的語句,因爲雖然當天不能賣那麼多的股票,但是可以從昨天轉移過來
dp[i][j]=max(dp[i][j],dp[i-1][j]);
}
if(i<W+2) continue; //因爲這裏沒有continue會re
int tail=0,head=1; //這裏有錯原來是 int tail=1,head=0; 發生了從8到3的蛻變
for(int j=0;j<=maxp;j+=1){ /*買進*/
while(/*j-J[head]<as[i]*/J[head] + as[i] < j&&head<=tail) head+=1; //維護單調隊列的長度
int newdp=dp[i-W-1][j]+j*ap[i];
while(head<=tail&&newdp>q[tail]) tail-=1;
tail+=1;
q[tail]=newdp,J[tail]=j;
//j[tail]這一步很重要,因爲是多重揹包,每一次入貨出貨都有限制,
//而由於使用單調隊列取得的最優解不一定符合限制條件,會過時
//while(/*j-J[head]<as[i]*/J[head] + as[i] < j&&head<=tail) head+=1; //維護單調隊列的長度
if(head<=tail) dp[i][j]=max(dp[i][j],q[head]-j*ap[i]);
}
tail=0,head=1;//這裏有錯原來是 int tail=1,head=0;
for(int j=maxp;j>=0;j-=1){ /*賣出*/
while(/*J[head]-j<bs[i]*/J[head] - bs[i] > j&&head<=tail) head+=1; //維護單調隊列的長度
int newdp=dp[i-W-1][j]+j*bp[i];
while(head<=tail&&newdp>q[tail]) tail-=1;
tail+=1;
q[tail]=newdp,J[tail]=j;
//j[tail]這一步很重要,因爲是多重揹包,每一次入貨出貨都有限制,
//而由於使用單調隊列取得的最優解不一定符合限制條件,會過時
//while(/*J[head]-j<bs[i]*/J[head] - bs[i] > j&&head<=tail) head+=1; //維護單調隊列的長度
if(head<=tail) dp[i][j]=max(dp[i][j],q[head]-j*bp[i]);
}
if(i==n){
for(int j=0;j<=maxp;j+=1){
ans=max(ans,dp[n][j]);
}
}
}
printf("%d\n",/*dp[n][0]*/ans);
}
return 0;
}
簡明版
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#define maxn 2052
using namespace std;
int ap[maxn],bp[maxn],as[maxn],bs[maxn];
int dp[maxn][maxn];
int q[maxn],j[maxn];
int n,maxp,w,ans;
int main()
{
int t;
scanf("%d",&t);
while(t--){
memset(dp,128,sizeof(dp));
ans=0;
scanf("%d %d %d",&n,&maxp,&w);
for(int i=1;i<=n;i+=1){
scanf("%d %d %d %d",&ap[i],&bp[i],&as[i],&bs[i]);
}
dp[0][0]=0;
for(int i=1;i<=w+1;i+=1){
for(int j=0;j<=maxp&&j<=as[i];j+=1){
dp[i][j]=-j*ap[i];
}
}
for(int i=1;i<=n;i+=1){
for(int j=0;j<=maxp;j+=1){
dp[i][j]=max(dp[i][j],dp[i-1][j]);
}
if(i<w+2) continue;
int tail=0,head=1;
for(int j=0;j<=maxp;j+=1){
while(j[head] + as[i] < j&&head<=tail) head+=1;
int newdp=dp[i-w-1][j]+j*ap[i];
while(head<=tail&&newdp>q[tail]) tail-=1;
tail+=1;
q[tail]=newdp,j[tail]=j;
if(head<=tail) dp[i][j]=max(dp[i][j],q[head]-j*ap[i]);
}
tail=0,head=1;
for(int j=maxp;j>=0;j-=1){
while(j[head] - bs[i] > j&&head<=tail) head+=1;
int newdp=dp[i-w-1][j]+j*bp[i];
while(head<=tail&&newdp>q[tail]) tail-=1;
tail+=1;
q[tail]=newdp,j[tail]=j;
if(head<=tail) dp[i][j]=max(dp[i][j],q[head]-j*bp[i]);
}
if(i==n){
for(int j=0;j<=maxp;j+=1){
ans=max(ans,dp[n][j]);
}
}
}
printf("%d\n",/*dp[n][0]*/ans);
}
return 0;
}