单调队列

股票交易——单调队列优化DP

回眸只為那壹抹淺笑 提交于 2019-11-30 17:03:11
题目描述 思路   蒟蒻还是太弱了,,就想到半个方程就GG了,至于什么单调队列就更想不到了。   $f[i][j]$表示第$i天有j$张股票的最大收益。   那么有四种选择: 不买股票:$f[i][j]=max(f[i][j],f[i-1][j])$ 买$j$张股票,之前没有买:$f[i][j]=-j*ap[i]$ 买$j$张股票,之前有过交易,中间间隔了$w$天:$f[i][j]=max(f[i][j],f[i-w-1][k]-(j-k)*ap[i])$ 卖$j$张股票,之前有过交易(废话),中间间隔了$w$天,$f[i][j]=max(f[i][j],f[i-w-1][k]+(k-j)*bp[i])$   方程列出来了,还是很好理解的。那么怎么优化呢?我们发现$i,j,k$都要枚举$O(n^3)$的复杂度是会$T$的,我们需要用一些优化。   我们发现:3转移中$f[i-w-1][k]-(j-k)*ap[i]=f[i-w-1][k]+k*ap[i]-j*ap[i]$,这样我们在第i天时只要找出最大的$f[i-w-1][k]+k*ap[i]$即可,因为前两维$i,j$已知,$j*ap[i]$是常数。   用一个递减的单调队列维护使$f[i-w-1][k]+k*ap[i]$最大的$k$,每次取队首转移即可,注意如果$as[i]<j-k$(即买不了这么多股票)时,需要把队首弹出。

[题解]luogu_P3084(单调队列dp

China☆狼群 提交于 2019-11-30 16:55:52
https://www.cnblogs.com/bztMinamoto/p/9375444.html 这题还可以dp做(我肯定想不出来 设$f[i]$为强制放在$i$的最大方案数,根据限制所有包含$i$的区间都不能再有点,最大只能从这些区间最靠左的左端点-1转移,最小不能跨过某个整区间转移,这样这个区间里就没有点,这样决策区间的左右端点$l[i],r[i]$就可以知道了 可是$l[i],r[i]$该怎么计算呢?发现这些左右端点是和区间端点密切相关的,再加思索发现类似于决策单调性 ? 一样的效果,区间内的决策点大概都是一样的,一开始我们先在各个区间的端点更新端点的取值,然后在正反扫一遍更新一遍所有点的lr取值 只能这么强行理解了,可能需要积累才能想到这些东西吧 这样$f[i]=max(f[j])+1(l[i]<=j<=r[i])$, 感觉l,r应该是单调的,实际上更新的时候$r[i]=min(r[i],r[i+1]),l[i]=max(l[i],l[i-1])$,能看出单调性是对的 然后 类似于NOIP普及2017T4 单调队列即可 代码细节较多也是抄的 #include<bits/stdc++.h> using namespace std; const int maxn=2e5+9; int n,m,l[maxn],r[maxn];//包含i的区间决策左端点/右端点 int hd

单调队列优化DP || [NOI2005]瑰丽华尔兹 || BZOJ 1499 || Luogu P2254

偶尔善良 提交于 2019-11-30 06:32:43
题外话:题目极好,做题体验极差 题面: [NOI2005]瑰丽华尔兹 题解: F[t][i][j]表示第t时刻钢琴位于(i,j)时的最大路程 F[t][i][j]=max(F[t-1][i][j],F[t-1][a][b]+1) (mp[i][j]可以到达,(a,b)直接到(i,j)之间没有家具,即路径合法) 因为船的倾斜是连续的,所以可以考虑按时间段来进行dp F[t][i][j]表示前t个时间段结束后,钢琴位于(i,j)的最大路程 F[t][i][j]=max(F[t][i][j],F[t-1][a][b]+Dis(a,b,i,j)) (mp[i][j]可达,Dis(a,b,i,j)<=T[t]-S[t]+1,(a,b)直接到(i,j)之间没有家具,即路径合法) 考虑使用单调队列优化dp 以下“OK”意味着mp[i][j]不出地图,且(i,j)上无家具,是可以到达的合法位置,且路径合法 路径合法可以通过在单调队列时遇到mp[i][j]=='x'的情况直接清空队列来快速实现,当然也可以通过写前缀和来判断实现 注意在写单调队列时入队应该放在维护F[t][i][j]前,因为可以停留在(i,j) Case 1:D[t]==1 此时船向北倾斜,则b=j(i大到i小) F[t][i][j]=max(F[t][i][j],F[t-1][a][j]+a-i) (OK,a-i<=T[t]-S[t

卖饲料——单调队列优化dp

强颜欢笑 提交于 2019-11-30 05:47:29
题目描述 约翰开车来到镇上,他要带K吨饲料回家。运送饲料是需要花钱的,如果他的车上有X吨饲料,每公里就要花费X^2元,开车D公里就需要D* X^2元。约翰可以从N家商店购买饲料,所有商店都在一个坐标轴上,第i家店的位置是Xi,饲料的售价为每吨Ci元,库存为Fi。 约翰从坐标X=O开始沿坐标轴正方向前进,他家在坐标X=E上。为了带K吨饲料回家, 约翰最少的花费是多少呢? 假设所有商店的库存之和不会少于K。 举个例子,假设有三家商店,情况如下所示: 坐标 X=1 X=3 X=4 E=5 库存 1 1 1 售价 1 2 2 如果K=2,约翰的最优选择是在离家较近的两家商店购买饲料,则花在路上的钱是1+4=5,花在商店的钱是2+2=4,共需要9元。 思路 $dp[i][j]$表示到了$i$带有$j$吨饲料的最少花费。(注意此时i商店还没有买 ) 在每个商店我们可以选择买或者不买,枚举$i-1$之前带有的饲料$k$,那么$dp[i]][j]=min(dp[i-1][k]+j*j*(d[i]-d[i-1])+(j-k)*c[i])$ 整理一下:$dp[i][j]=min(dp[i-1][k]-k*c[i]+j*j*(d[i]-d[i-1])+j*c[i])$ 单调队列维护使dp[i-1][k]最小的 k转移即可。 code #include<bits/stdc++.h> using

单调队列优化DP || [Poi2014]Little Bird || BZOJ 3831 || Luogu P3572

随声附和 提交于 2019-11-30 04:23:36
题面: [POI2014]PTA-Little Bird 题解: N<=1e6 Q<=25 F[i]表示到达第i棵树时需要消耗的最小体力值 F[i]=min(F[i],F[j]+(D[j]>=D[i])) (j>=i-K) 使用单调队列维护 越小的越优,在写单调队列时,让F值最小的数越前 因为F[i]-F[j]最多等于1 然后如果F值相同,则D越大的越优,因为D越大,后面不用+1的概率越大 大概就是这样 代码: 1 #include<cstdio> 2 #include<cstring> 3 #define min(a,b) ((a)<(b)?(a):(b)) 4 #define max(a,b) ((a)>(b)?(a):(b)) 5 using namespace std; 6 int rd(){ 7 int x=0; char c=getchar(); 8 while(c<'0'||c>'9') c=getchar(); 9 while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} 10 return x; 11 } 12 const int maxn=1e6+5,maxq=30,inf=1<<30; 13 int N,D[maxn],F[maxn],Q,K,f1,f2; 14 int que[maxn]; 15 int main()

POJ 1742 (单调队列优化多重背包+混合背包)

廉价感情. 提交于 2019-11-30 02:07:33
(点击此处查看原题) 题意分析 给你n种不同价值的硬币,价值为val[1],val[2]...val[n],每种价值的硬币有num[1],num[2]...num[n]个,问使用这n种硬币可以凑齐[1,m]内多少价值(换句话说,就是可以恰好支付的价格有多少) 解题思路 一开始觉得这个题也不是很难,就是多重背包问题,但是用二进制优化的多重背包写法TLE后,陷入了深思... 看了数据范围,二进制优化的时间复杂度为O(∑ log(num[i] * V),加上多组输入后....应该是没被冤枉了..... 二进制都不行了,怎么办呢?只能去用单调队列优化多重背包问题了,其时间复杂度为O(n*V),时间刚刚好卡过去... 但是这里又出了一个问题,我用单调队列优化求解仍然得到了TLE? QAQ,难道还有比单调队列更优的解法?借鉴大佬的题解后,发现这个题目严格意义上算是一个混合背包问题,而用单调队列处理完全背包问题的时候,效率很低,所以将将这个题目按照混合背包分别处理后,就可以AC了。 (单调队列优化的讲解可以看看这个,讲的很清晰: http://www.cppblog.com/flyinghearts/archive/2010/09/01/125555.html ) 代码区 #include<iostream> #include<cstdio> #include<algorithm>

题解 P3800 【Power收集】

守給你的承諾、 提交于 2019-11-29 05:04:37
先无良宣传一下博客 \(wwwwww\) 文章列表 - 核融合炉心 - 洛谷博客 知识点 : \(DP\) 优化 , 单调队列 题意: 有一个 \((N\times M)\) 大小的矩阵 部分矩阵中的点 带有价值 可以选择第一行 , 任何一个位置作为起点 . 对于当前的位置 \((i,j)\\) (表示在第 \(i\) 行第 \(j\) 列) 可以转移到: \((i+1,\ [j-T , j+T]\ )\) 中任意一个点 \((j-T>0\ ,\ j+t\leqslant M)\) 并且获得当前所在点的价值 . 求 : 可以取得的 最大价值和 样例解释: 1.灵梦从 \((1,1)\) 出发 : 总价值 \(+3\) , 现在为 \(3\) 2.灵梦转移到 \((2,2)\) : 总价值 \(+3\) ,现在为 \(6\) 3.灵梦转移到 \((3,3)\) : 总价值 \(+3\) ,现在为 \(9\) 故 , 总价值为 \(9\) 分析题意: 很显然 这是一道 \(DP\) 状态转移方程 极其简单 : 用 \(f[i][j]\) 表示在点 \((i,j)\) 能到达的最大价值和 , 则有: \(f[i][j] = max(f[i-1][k]) + v[i][j]\ ,\ (k\in [j-T , j+T]\ )\) 暴力: 直接枚举所有点 , 再枚举能转移到他的点 ? 复杂度

28 August

本秂侑毒 提交于 2019-11-28 20:31:00
单调队列复习。 投资 (invest) 给定一带符号整数数列,求长度为 \([s, e]\) 的子区间的和的最大值。(最大子段和) 降二维为一维,for循环枚举区间右端点。预处理前缀和,问题转化为找到最小的左端点。 使用单调队列维护查找范围内最小值。参看 单调队列总结 。 单调队列算法实现: 弹出单调队列左端的失效元素。 弹出单调队列右端的破坏单调性的元素。如在最小值单调队列中,剔除比 即将加入的元素 更大的元素,因为后者已对答案无未来贡献。(比前者先失效,未来不会是更小值。) 加入新元素。计算并统计当前单调队列维护的最优值。 int q[N], l, r; int m=1; int main() { n=read(), s=read(), e=read(); // s 区间最小长度, e 区间最大长度 for (int i=1; i<=n; i++) a[i] += a[i-1] + read(); for (int i=s; i<=n; i++) { while (l < r && i-q[l] > e) l++; while (l < r && a[i-s] < a[q[r-1]]) r--; q[r++] = i-s; m=max(m, a[i] - a[q[l]]); } write(m); return 0; } 来源: https://www.cnblogs.com

单调队列优化多重背包问题 + 例题

元气小坏坏 提交于 2019-11-28 18:44:09
例题: https://www.acwing.com/problem/content/6/ 多重背包除了可以使用二进制加速,还可以使用单调队列加速,并且单调队列会更快 正常的多重背包的dp方程: 其中 k 为物品的多少, v[i]为物品的体积, w[i]为物品的价值 可以看到转移的时候,dp[i][j]只和dp[i][j-k*v[i]]有关,并且是取动态的固定区间大小的区间最值,可以考虑使用优先队列优化。 使用优先队列要求我们j由小到大遍历,因此此题不方便使用一维数组简化空间,但是可以使用滚动数组减少空间 (假如使用一维数组,那么之前计算过的数值就会无限叠加,如图j-3v会叠加到j 然后j再带着j-3v的值不断往前叠加) 使用滚动数组的时候,设 dp[2][i] i:表示此时背包体积多少 dp数组则表示当体积为i的时候可以获得的最优解 每次使用的时候dp[t][i] , 每次需要滚动的时候t^=1 即可 还有一个问题,就是优先队列如何维护数值。 假如直接维护dp[i][k] + (j-k)/v[i] * w[i] (也就是维护dp的值),那么i增加的时候,之前的dp对dp[i]的贡献全部会改变,比如: 当j+=v的时候 此时优先队列里维护的东西就变了。 所以需要维护一个不受距离影响的值,具体看代码: #include<bits/stdc++.h> using namespace

cogs 495. 滑动窗口 单调队列

折月煮酒 提交于 2019-11-28 13:54:39
495. 滑动窗口 ★★ 输入文件: window.in 输出文件: window.out 简单对比 时间限制:2 s 内存限制:256 MB 【问题描述】 给你一个长度为N的数组,一个长为K的滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位,如下表: Window position Min value Max value [ 1 3 -1 ] -3 5 3 6 7 -1 3 1 [ 3 -1 -3 ] 5 3 6 7 -3 3 1 3 [ -1 -3 5 ] 3 6 7 -3 5 1 3 -1 [ -3 5 3 ] 6 7 -3 5 1 3 -1 -3 [ 5 3 6 ] 7 3 6 1 3 -1 -3 5 [ 3 6 7 ] 3 7 你的任务是找出窗口在各位置时的max value,min value. 【输入格式】 第一行n,k,第二行为长度为n的数组 【输出格式】 第一行每个位置的min value,第二行每个位置的max value 【输入输出样例】 window.in 8 3 1 3 -1 -3 5 3 6 7 window.out -1 -3 -3 -3 3 3 3 3 5 5 6 7 【数据范围】 20%:n≤500; 50%:n≤100000;100%:n≤1000000; 多年未敲(不禁心生疑惑 我一共才学了几年!?