luogu 2569 [SCOI2010]股票交易
分析
显然的DP,就不多说了吧
推荐题解:题解 P2569 【[SCOI2010]股票交易】
Part 1 状态
涉及到的状态:天数,股票,买卖
转移的时候,应只与股票有关,是否买卖有一定关系,但可以从前一天转移
所以:dp[天数][这一天后所持股票数] = 最大收入
Part 2 初值
说实话,我发现边界与初值是很重要的一部分
看这道题,由于股票不可能凭空出现,需要购买,
所以不可能赋值为零,初值应该是持有这么多股票的买入价
求最大,还是赋极小值吧
Part 3 转移
少不得要分类讨论
初值是持有这么多股票的买入价,也就是空买(买入有上限)
而也可以选择不买不卖:
接下来考虑转移买卖;
首先,本身天数就少于w的不做考虑,会出现负下标
我们可以只考虑i - w - 1的情况
嗯?不是1~i - w - 1都可以吗?
你看这句话:
不是把前面的最优情况都考虑到了?
好吧,有点道理
考虑买卖的方程:
难道要多一维?
当然不可能
看限制,固定区间的最值,考虑考虑单调队列
稍微变个型:
这样就好了,单调队列直接维护dp[i-w-1][k]+k*bp[i]就好
代码
1 /************************ 2 User:Mandy.H.Y 3 Language:c++ 4 Problem:luogu2569 5 Algorithm: 6 ************************/ 7 8 #include<bits/stdc++.h> 9 10 using namespace std; 11 12 const int maxn = 2005; 13 14 int t,maxp,w; 15 int dp[maxn][maxn]; 16 int ap[maxn],bp[maxn],as[maxn],bs[maxn]; 17 int q[maxn],l,r; 18 19 template<class T>inline void read(T &x){ 20 x = 0;bool flag = 0;char ch = getchar(); 21 while( ! isdigit(ch)) flag |= ch == '-',ch = getchar(); 22 while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar(); 23 if(flag) x = -x; 24 } 25 26 template<class T>void putch(const T x){ 27 if(x > 9) putch(x / 10); 28 putchar(x % 10 | 48); 29 } 30 31 template<class T>void put(const T x){ 32 if(x < 0) putchar('-'),putch(-x); 33 else putch(x); 34 } 35 36 void file(){ 37 freopen("2569.in","r",stdin); 38 freopen("2569.out","w",stdout); 39 } 40 41 void readdata(){ 42 read(t);read(maxp);read(w); 43 for(int i = 1;i <= t; ++ i){ 44 read(ap[i]);read(bp[i]); 45 read(as[i]);read(bs[i]); 46 } 47 } 48 49 void work(){ 50 memset(dp,128,sizeof(dp)); 51 //注意初值与边界,不一定为0 52 //赋为极小值,因为股票必须靠买,而不能直接为0; 53 //不必为j = 0时赋零,因为j=0时 -1 * j * as[i] = 0 54 for(int i = 1;i <= t ; ++ i){ 55 56 for(int j = 0;j <= maxp; ++ j){ 57 if(j <= as[i]) dp[i][j] = -1 * j * ap[i]; 58 dp[i][j] = max(dp[i][j],dp[i-1][j]); 59 } 60 61 if(i <= w) continue; 62 //我们可以只考虑i - w - 1的情况 63 //dp[i][j] = max(dp[i][j],dp[i-1][j]);考虑到了之前的最优情况 64 l = r = 0; 65 for(int j = 0;j <= maxp; ++ j){//买入 66 while(l < r && j - q[l] > as[i]) l++; 67 while(l < r && dp[i-w-1][q[r-1]] + q[r-1] * ap[i] <= dp[i-w-1][j] + j * ap[i]) r--; 68 q[r++] = j; 69 if(l < r) dp[i][j] = max(dp[i][j],dp[i - w-1][q[l]] - (j - q[l]) * ap[i]); 70 } 71 72 l = r = 0; 73 for(int j = maxp;j >= 0; -- j){//卖出 74 while(l < r && q[l] - j > bs[i]) l++; 75 while(l < r && dp[i-w-1][q[r-1]] + q[r-1] * bp[i] <= dp[i-w-1][j] + j * bp[i]) r--; 76 q[r++] = j; 77 if(l < r) dp[i][j] = max(dp[i][j],dp[i - w-1][q[l]] + (q[l] - j) * bp[i]); 78 } 79 } 80 81 put(dp[t][0]); 82 83 } 84 85 int main(){ 86 // file(); 87 readdata(); 88 work(); 89 return 0; 90 }
非做顽石不可,哪管他敬仰暗唾