本文共 3158 字,大约阅读时间需要 10 分钟。
记录那写抄题解水过的单调队列优化DP
用到单调队列优化的情况:
实现步骤:
其实和单调队列差不多,只是队首队尾的弹出条件相对复杂,涉及斜率?
memset(f, 128, sizeof f)
Description
Solution
状态应该是比较好想的,数据范围只有两千,涉及量有天数和股票数,所以可以设 \(f_{i, j}\) 表示到第 \(i\) 天,手里还有 \(j\) 个股票时的最大价值
分情况讨论
为什么一定是这一天?回看刚刚讨论的第 2 种情况,我们已经把某一天以前的最优答案转移到了该天,所以从那一天转移,相当于从那一天包括前面任何一天开始转移,省去了大把时间。
设第 \(i - W - 1\) 有 \(k\) 枚股票,因为有 \(as\) 的限制,所以 \(j - as\) 是底线,买进 \(j - k\) 张股票,要花去 \((j - k) \times {ap}i\) 转移方程为:
因为是卖股票,\(k\) 要比 \(j\) 大,但要 $\le j + bs_i $;这次交易卖了 \(k - j\) 张股票,赚得 \((k - j) \times {bp}_i\),整理一下,转移方程为:
但是,这样滴复杂度显然到了 \(n^3\) ,让我们考虑优化。
回到那个方程:\(f_{i,j} = \max \{ f_{i,j}, f_{i - W - 1, k} - (k - j) \times {ap}_i \} (j - {as}_i \le k < j)\)
运用乘法分配律得:$$f_{i,j} = \max { f_{i,j}, f_{i - W - 1, k} - k \times {ap}_i + j \times {ap}_i } (j - {as}_i \le k < j)$$
发现最后一项与 \(k\) 无关,\(k\) 的范围是不断移动的,符合单调队列优化的条件,维护一个区间最大值就好了
因为第四种情况调用 \(k\) 比 \(j\) 大,所以需要倒序枚举
Code
/*Work by: Suzt_ilymicsKnowledge: ??Time: O(??)*/#include#include #include #include #define LL long long#define orz cout<<"lkp AK IOI!"< << 1) + (s << 3) + ch - '0' , ch = getchar(); return f ? -s : s;}int main(){ memset(f, 128, sizeof f); T = read(), MaxP = read(), W = read(); for(int i = 1; i <= T; ++i){ ap = read(), bp = read(), as = read(), bs = read(); for(int j = 0; j <= as; ++j){//初始情况 f[i][j] = -1 * j * ap; } for(int j = 0; j <= MaxP; ++j){//不进行任何操作 f[i][j] = max(f[i][j], f[i - 1][j]); } if(i <= W) continue;//因为买入和卖出要在w天之后进行 int l = 1, r = 0; for(int j = 0; j <= MaxP; ++j){//买入操作 while(l <= r && q[l] < j - as) l++;//超出买入数量就扔掉 while(l <= r && f[i - W - 1][q[r]] + q[r] * ap <= f[i - W - 1][j] + j * ap) r--;//更新单调队列元素 q[++r] = j; if(l <= r){ f[i][j] = max(f[i][j], f[i - W - 1][q[l]] + q[l] * ap - j * ap); } } l = 1, r = 0; for(int j = MaxP; j >= 0; --j){//买出操作 //因为使用后面的更新前面的,所以需要倒叙枚举 while(l <= r && q[l] > j + bs) l++;//超出买出数量就扔掉 while(l <= r && f[i - W - 1][q[r]] + q[r] * bp <= f[i - W - 1][j] + j * bp) r--;//更新单调队列元素 q[++r] = j; if(l <= r){ f[i][j] = max(f[i][j], f[i - W - 1][q[l]] + q[l] * bp - j * bp); } } } int ans = -INF; for(int i = 0; i <= MaxP; ++i){ ans = max(ans, f[T][i]); } printf("%d", ans); return 0;}
转载地址:http://bbfkz.baihongyu.com/