一类利用队列优化的DP
I.导入:
这是一个\(O(n^2)\)的状态和转移方程:
\begin{aligned}
f(i-1,j-1)+k \ (1\leq j)\\
\max_{k \in [0,i]}{f(i-1,k)} (j=1)
\end{aligned}
\right.\]
这个方程目测是\(\Theta(n^2)\)的,但是实际上,上面的那个方程只是把数组整体位移了,下面的方程只是在位移后的数组开端添上了一个数,这个完全可以通过队列来实现,\(+k\)的操作,用一个整体的差分量就能实现,时间复杂度\(O(n)\)。这个方法最伟大的一点在于,它的复杂度比状态维度还要低一维,这是让人难以想到这种方法的一大原因。
II.xj2020 画画
\(n<=5000, m<=1e7\).显然当两种颜色的 a 相等的时候,它们完全等价,所以我们建一个桶 \(b_i\) 表示长度限制为 i 的颜色个数,再设\(f_{i,j,k}\)表示 DP 到了 i 号格子,当前颜色的长度限制是 j (其实是有点 hash 的表示颜色),当前颜色已经连续了 k 个,则状态转移方程为:
\begin{aligned}
f(i-1,j,k-1) \ (1\leq k)\\
b_j\sum_{j'!=j}{\sum_{k'}{f(i-1,j',k')}} + (b_j-1)\sum_{k'}{f(i-1,j,k')} (j=1)
\end{aligned}
\right.\]
这个状态状态转移方程上面和下面各是\(\Theta(n^3)\)的,但是我们可以发现这个转移方程,上面的可以用队列来实现整体位移,下面的可以对每个队列维护一个和,再维护一下总和,就能实现\(\Theta(n^2)\)了,主要代码如下:
for (int i = 1; i <= n; i++)
{
q[i].push(b[i]);
lastsum += (S[i] = b[i]);
}
for (int i = 2; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (!b[j]) continue;
ins[j] = ((LL)lastsum * b[j] % mod + mod - S[j]) % mod;
}
for (int j = 1; j <= n; j++)
{
if (!b[j]) continue;
(S[j] += ins[j]) %= mod;
(lastsum += ins[j]) %= mod;
q[j].push(ins[j]);
}
for (int j = 1; j <= n; j++)
{
if (!b[j]) continue;
while (q[j].size() > j)
{
(S[j] += mod - q[j].front()) %= mod;
(lastsum += mod - q[j].front()) %= mod;
q[j].pop();
}
}
}
fout << lastsum << Endl;
实现难度不大,主要难度在于设出状态和方程,因为这个状态有三维,很多时候我们就默认它的时间复杂度大于等于三次方,而这题偏偏又很容易得到只有两维的状态设置,很多人以为“肯定不如二维的状态设置”,但实际上,这个三维的状态可以优化到二次方,而这个二维的状态设置没法实现\(\Theta(1)\)的转移
III.xj2020 字符串
\(n<=2e5,m<=20\).假设 DP 到了前 i 个点,当前的两个子序列,一个肯定有一个以 i 号字符串结尾,我们只需要存另一个子序列以什么结尾;而子序列的长度都相同,说明我们只关心这个子序列最后一个串是哪一个。设\(f[i][j]\)表示,DP 到了前 i 个点,一个子序列的结尾是 i,另一个子序列的结尾是 j 时的最短长度。综合把 i 接到 i-1 上 和把 i 接到 i-1 之前的两种情况,可以得到状态转移方程:
\begin{aligned}
\min\{f(i-1,k)+cost(k,i)\} \ (j=i-1)\\
f(i-1,k)+\text{cost}(i-1,i)(else)
\end{aligned}
\right.\]
这个状态转移方程本身已经很难想到了,需要很熟稔的分类讨论的能力。优化上,可以使用栈——上面那东西是整体加法,下面那东西是在栈底追加一个值。考虑这个 min 怎么\(\Theta(1)\)求:对于 cost 相等的 k ,显然它们是等价的。所以把已有的字符串倒序放进一个 Trie 里面,查询时正着顺着 \(S_i\) 走,每到一个点用\(m-dep+f_X\)更新答案,其中\(f\)是树上前缀最小值,这样会有重复情况,但是显然不影响。用整体差分就能实现 f 值的修改。
IV.「2020-09-20 五校联考」球与洞 (ballhole)
这个是国冬模拟费用流的第二题,居然被搬来了五校联考。。。
首先使用微扰法,把球和洞画成两排,把每个球连向它的洞,显然这些连线不能相交,这就及其有利于我们进行 DP。把球和洞摆成一排并排序,设\(f[i][i]\)表示,当 \(j>0\)时表示剩下确定选下了 \(-j\)个洞待匹配的最小代价;当 \(j<0\)时表示 DP 到了第 \(i\) 个位置、剩下多少个球还待匹配的、费用提前计算的代价(提前减去绝对值函数的部分呀),那么当前位置是个球的时候,状态转移方程是:
\begin{aligned}
-pos_i \ (j>0)\\
pos_i (else)
\end{aligned}
\right.\]
当目前位置是个洞的时候,状态转移方程就是:
\begin{aligned}
-pos_i \ (j<0)\\
pos_i (else)
\end{aligned})
\right.\]
然后把第二个式子分析一下,发现当且仅当\(j=0\)的时候需要取 min, 其他时候只需要直接取右手边的作为最小值即可,所以我们把 DP 数组切成三段,下标是负的一段,0一段,正的一段,就可以实现 \(\Theta(n)\)。评测记录
总结:有的时候转移的复杂度比较大/状态的维度比较大的时候,我们不妨退而求其次,通过把状态升一维的代价把转移降低一维,也许就可以通过队列优化,反而能优化掉一维。
一类利用队列优化的DP的更多相关文章
- hdu-3401-Trade-单调队列优化的DP
单调队列入门题... dp[i][j]:第i天.手中拥有j个股票时,获得的最大利润. 若第i天不买不卖:dp[i][j]=max(dp[i][j],dp[i-1][j]); 若第i天买 ...
- 【NOIP2017】跳房子 题解(单调队列优化线性DP)
前言:把鸽了1个月的博客补上 ----------------- 题目链接 题目大意:机器人的灵敏性为$d$.每次可以花费$g$个金币来改造机器人,那么机器人向右跳的范围为$[min(d-g,1),m ...
- Trade-----HDU3401----单调队列优化的DP
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3401 题目意思: 有T天,你每天可以以API买进,BPI卖出,最多买ASI个,最多卖BSI个 最多只能 ...
- poj1821 Fence【队列优化线性DP】
Fence Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 6122 Accepted: 1972 Description ...
- 洛谷p1725 露琪诺 单调队列优化的DP
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int ...
- BestCoder Round #89 02单调队列优化dp
1.BestCoder Round #89 2.总结:4个题,只能做A.B,全都靠hack上分.. 01 HDU 5944 水 1.题意:一个字符串,求有多少组字符y,r,x的下标能组成等比数列 ...
- 单调队列以及单调队列优化DP
单调队列定义: 其实单调队列就是一种队列内的元素有单调性的队列,因为其单调性所以经常会被用来维护区间最值或者降低DP的维数已达到降维来减少空间及时间的目的. 单调队列的一般应用: 1.维护区间最值 2 ...
- bzoj1855: [Scoi2010]股票交易 单调队列优化dp ||HDU 3401
这道题就是典型的单调队列优化dp了 很明显状态转移的方式有三种 1.前一天不买不卖: dp[i][j]=max(dp[i-1][j],dp[i][j]) 2.前i-W-1天买进一些股: dp[i][j ...
- 队列优化和斜率优化的dp
可以用队列优化或斜率优化的dp这一类的问题为 1D/1D一类问题 即状态数是O(n),决策数也是O(n) 单调队列优化 我们来看这样一个问题:一个含有n项的数列(n<=2000000),求出每一 ...
随机推荐
- javascript-jquery对象的其他处理
一.对元素进行遍历操作 如果要遍历一个jquery对象,对其中每个匹配元素进行相应处理,那么可以使用each()方法. $("div").each(function(index,e ...
- springboot 事务执行全流程分析
springboot 事务执行全流程分析 目录 springboot 事务执行全流程分析 1. 事务方法执行前的准备工作 2. 业务代码的调用 3. 事务方法执行后处理 4. 业务代码在事务和非事务中 ...
- Mybatis 动态Sql练习
建表 CREATE TABLE `student` ( `s_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT ...
- 吴恩达课后习题第二课第三周:TensorFlow Introduction
目录 第二课第三周:TensorFlow Introduction Introduction to TensorFlow 1 - Packages 1.1 - Checking TensorFlow ...
- 在Vue前端项目中,附件展示的自定义组件开发
在Vue前端界面中,自定义组件很重要,也很方便,我们一般是把一些通用的界面模块进行拆分,创建自己的自定义组件,这样操作可以大大降低页面的代码量,以及提高功能模块的开发效率,本篇随笔继续介绍在Vue&a ...
- 2021.8.16考试总结[NOIP模拟41]
T1 你相信引力吗 肯定是单调栈维护.但存在重复值,还是个环,不好搞. 发现取区间时不会越过最大值,因此以最大值为断点将环断为序列.在栈里维护当前栈中有多少个与当前元素相等的元素,小分类讨论一下. 最 ...
- sum-root-to-leaf-numbers leetcode C++
Given a binary tree containing digits from0-9only, each root-to-leaf path could represent a number. ...
- cloudstack部署
参考文档 https://blog.csdn.net/u012124304/article/details/80960504#Mysql_37 cloudstack的rpm包下载地址 http://d ...
- 一维前缀和 连续数组和为k
给定一个整数数组和一个整数 k ,请找到该数组中和为 k 的连续子数组的个数. 滑动窗口没办法解决有负数的情况 方法一: 预处理 前缀和 sum_ij = preSum[j] - preSum[i-1 ...
- springcloud zuul shiro网关鉴权并向服务传递用户信息
1.pom文件 <dependencies> <!--eureka客户端--> <dependency> <groupId>org.springfram ...