可惜没如果=_=
时光的河入海流

Trade

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5242    Accepted Submission(s): 1810


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.
 

 

Sample Input
1 5 2 0 2 1 1 1 2 1 1 1 3 2 1 1 4 3 1 1 5 4 1 1
 

 

Sample Output
3
 

 

Author
lxhgww
 

 

Source
 

 

Recommend
lcy   |   We have carefully selected several similar problems for you:  3400 3403 3404 3402 3415 
 

dp[i][j]:表示第i天手上持有j股的最大利益。分情况:

dp[i][j]=dp[i-1][j] 不交易 
dp[i][j]=max( dp[r][k]-ap[i]*(j-k) | j>=k,r<=i-w-1) 买进 
dp[i][j]=max(dp[r][k]+bp[i]*(k-j) | j<=k,r<=i-w-1) 卖出 
由于dp[i][j]不会小于之前的 dp[k][j],k < i ,所以r=i-w-1 
这里有个可以使用单调队列的特征 
dp[i][j]=(dp[r][k]+ap[i] * k)- ap[i] * j; 
求dp[i][j]时只需求之前最大的dp[r][k]+ ap[i] * k,所以可以用单调队列维护。 
卖出时同理。 

转自http://blog.csdn.net/carryheart/article/details/52441710

初始化须注意!

 1 #include "bits/stdc++.h"
 2 using namespace std;
 3 typedef long long LL;
 4 const int MAX=2005;
 5 int T,n,m,w;
 6 int f[MAX][MAX],ap[MAX],bp[MAX],as[MAX],bs[MAX];
 7 deque <int> q;
 8 int wo1(int i,int j){return f[i-w][j]+j*ap[i];}
 9 int wo2(int i,int j){return f[i-w][j]+j*bp[i];}
10 int main(){
11     freopen ("trade.in","r",stdin);
12     freopen ("trade.out","w",stdout);
13     int i,j;
14     scanf("%d",&T);
15     while (T--){
16         scanf("%d%d%d",&n,&m,&w);w++;
17         for (i=1;i<=n;i++) scanf("%d%d%d%d",ap+i,bp+i,as+i,bs+i);
18         for (i=1;i<=n;i++){
19             f[i][0]=0;
20             for (j=1;j<=m;j++)
21                 f[i][j]=-999999999;
22         }
23         for (i=1;i<=w;i++)
24             for (j=1;j<=as[i];j++)
25                 f[i][j]=-j*ap[i];
26         for (i=2;i<=w;i++)
27             for (j=1;j<=m;j++)
28                 f[i][j]=max(f[i][j],f[i-1][j]);
29         int zt;
30         for (;i<=n;i++){
31             while (!q.empty()) q.pop_back();
32             for (j=0;j<=m;j++){
33                 f[i][j]=max(f[i][j],f[i-1][j]);
34                 zt=f[i-w][j]+j*ap[i];
35                 while (!q.empty() && zt>wo1(i,q.back())) q.pop_back(); q.push_back(j);
36                 while (!q.empty() && j-q.front()>as[i]) q.pop_front();
37                 if (!q.empty())
38                     f[i][j]=max(f[i][j],wo1(i,q.front())-j*ap[i]);
39             }
40             while (!q.empty()) q.pop_back();
41             for (j=m;j>=0;j--){
42                 zt=wo2(i,j);
43                 while (!q.empty() && zt>wo2(i,q.back())) q.pop_back(); q.push_back(j);
44                 while (!q.empty() && q.front()-j>bs[i]) q.pop_front();
45                 if (!q.empty())
46                     f[i][j]=max(f[i][j],wo2(i,q.front())-j*bp[i]);
47             }
48         }
49         int ans=-999999999;
50         for (i=0;i<=m;i++) ans=max(ans,f[n][i]);
51         printf("%d\n",ans);
52     }
53     return 0;
54 }

 

遇到怎样的题使用单调队列: 
做动态规划时常常会见到形如这样的转移方程:

  f[x] = max or min{g(k) | b[x] <= k < x} + w[x]

  (其中b[x]随x单调不降,即b[1]<=b[2]<=b[3]<=…<=b[n])

  (g[k]表示一个和k或f[k]有关的函数,w[x]表示一个和x有关的函数) 
  例如上一题就是满足这样的方程,所以可以使用单调队列优化。 
  这个方程怎样求解呢?我们注意到这样一个性质:如果存在两个数j, k,使得j <= k,而且g(k) <= g(j),则决策j是毫无用处的。因为根据b[x]单调的特性,如果j可以作为合法决策,那么k一定可以作为合法决策,又因为k比j要优,(注意:在这个经典模型中,“优”是绝对的,是与当前正在计算的状态无关的),所以说,如果把待决策表中的决策按照k排序的话,则g(k)必然是不降的。

  这样,就引导我们使用一个单调队列来维护决策表。对于每一个状态f(x)来说,计算过程分为以下几步:

  1、 队首元素出队,直到队首元素在给定的范围中。

  2、 此时,队首元素就是状态f(x)的最优决策,

  3、计算g(x),并将其插入到单调队列的尾部,同时维持队列的单调性(不断地出队,直到队列单调为止)。

  重复上述步骤直到所有的函数值均被计算出来。不难看出这样的算法均摊时间复杂度是O(1)的。因此求解f(x)的时间复杂度从O(n^2)降到了O(n)。

单调队列指一个队列中的所有的数符合单调性(单调增或单调减),在信息学竞赛的一些题目上应用,会减少时间复杂度

 

posted on 2017-10-17 20:07  珍珠鸟  阅读(338)  评论(0编辑  收藏  举报