博主太菜,可能会炸联赛,于是恶补一下 QAQ
题目比较基础,动态更新
Tags
仅包含 提高组 内容。
- 类型:
区间 dp
,背包 dp
,树形 dp
,状压 dp
,计数 dp
,数位 dp
,概率/期望 dp
,环形 dp
,基环树 dp
。
- 优化:
单调栈/单调队列 优化
,其他数据结构 优化
,斜率 优化
,倍增 优化
Summarize
简单总结了部分基础类型的 dp 以及一些优化。
区间 dp
基础状态: \(f(l, r)\) 表示区间 \([l, r]\) ……
基础转移模型示例:\(f(l,r) = \min\limits_{k}\{f(l, k) + f(k+1, r)+\cdots\}\)。
基本实现:枚举区间长度,枚举左端点并计算出右端点,枚举断点。或者直接记搜。
树形 dp
树上动态规划。
基础状态:\(f(x, \cdots)\) 表示以 \(x\) 为根的子树……
由于树的递归性质,基本用 Dfs 实现。
状压 dp
常见于元素个数较少的情况。
基础状态:\(f(S, \cdots)\) 表示以 \(x\) 为根的子树……
集合使用二进制、位运算的思想压缩成一个整数并进行判断或转移。
计数 dp
常用于统计方案数。
设计状态是重点,转移看题意。
可能有一些组合计数的知识。
数位 dp
常见情况:统计值域在 \([a, b]\) 中满足……条件的数的个数/数位数字和/……(\(a, b\) 通常很大)
一般拆成 \(\text{ans}(b) - \text{ans}(a - 1)\) 计算,以记忆化搜索实现。
搜索函数的参数一般有当前位置,前面是否有前导零,枚举时是否受当前位大小限制。但大多数题目还会有其他限制。
数位 dp 的复杂度和位数有关。
概率/期望 dp
一般情况下,解决概率问题需要顺序循环,而解决期望问题使用逆序循环,如果定义的状态转移方程存在后效性问题,还需要用到转化成求解方程组的解并使用高斯消元。
部分题目还会牵扯到状压、矩阵加速等。
对分数取模记得逆元。
环形 dp
环上的 dp,一般的处理方法有断环为链然后 dp 两次或 \(n\) 次,或者复制一遍。
基环树 dp
环形 dp + 树形 dp。据说很烦,不会。
背包 dp
主要是挖出经典模型。
单调栈/单调队列 优化
一般会出现滑动最值差不多的模型,如:\(f(i) = \min\limits_{j<i}\{f(j)+\text{val}(i, j) \}\),其中 \(\text{val}(i, j)\) 为一个仅存在关于 \(i\) 或关于 \(j\) 的项的多项式,不存在同时关于 \(i, j\) 的项。
此时可以提出关于 \(i\) 的项,用单调队列维护 \(f(j)\) 和关于 \(j\) 的项,加速转移。
斜率 优化
上述 单调栈/单调队列 优化 的拓展。适用于 \(\text{val}(i, j)\) 中含有同时关于 \(i, j\) 的项时的情况。
一般可以假设来两个决策点 \(a, b(a<b<i)\),并设 \(a\) 劣于 \(b\)。我们可以得到一个不等式,然后变形为 \(\dfrac{y_a - y_b}{x_a - x_b} = \text{slope}(a, b)\) 的形式。最后用单调队列维护上/下凸包即可。
其他数据结构 优化
一般根据转移的特征,使用合适的数据结构优化转移。
倍增 优化
也许会有类似与 \(2^k\) 这种明显的提示。
一般把“转移 \(j\) 次”换成“转移 \(2^k\) 次”降下复杂度。
Content
- 「eJOI2017」Experience
树形 dp
- 「eJOI2018」山
- 「CSP2019-J」纪念品
背包 dp
- 「NOIp2018-普及」摆渡车
- 「AHOI2009」中国象棋
计数 dp
- 「LA 4394」String painter
区间 dp
- 「CSP2019-S」Emiya 家今天的饭
- 「Codeforces」Coloring Brackets
区间 dp
- 「USACO19DEC」Greedy Pie Eaters
区间 dp
- 「NOIp2018-提高」愤怒的小鸟
状压 dp
- 「Codeforces 372C」Watching Fireworks is Fun
单调栈/单调队列 优化
- 「Codeforces 16E」Fish
状压 dp
概率/期望 dp
- 「POI2014」Little Bird
单调栈/单调队列 优化
- 「POJ 1746」Minimizing maximizer
其他数据结构 优化 - 线段树
- 「POJ 2836」Rectangular Covering
状压 dp
- 「POJ 1821」Fence
单调栈/单调队列 优化
- 「HDU 3507」Print Article
斜率 优化
- 「HNOI2008」玩具装箱
斜率 优化
- 「HDU 2829」Lawrence
斜率 优化
- 「THUSC 2016」成绩单
区间 dp
- 「Codeforces 148D」Bag of mice
概率/期望 dp
- 「Luogu P1654」OSU!
概率/期望 dp
- 「Luogu P3413」SAC#1 - 萌数
数位 dp
- 「SDOI2016」征途
斜率 优化
- 「Luogu P1613」跑路
倍增 优化
「eJOI2017」Experience
update - 2020.7.27
设 \(f(x, 0), f(x, 1)\) 分别表示以 \(x\) 为根的子树,\(x\) 所在链为向下(非严格)递减、递增时的答案。
题目中要求求极差,那么结点 \(x\) 可能为最大值或最小值。
以向下递减为例,我们在所以满足 \(W_x \ge W_y\) 的所有子结点 \(y\) 中,将原本 \(y\) 的贡献用 \(x\) 作为新的最大值替换,并更新 \(f(x, 0)\) 的答案。向下递增也是同理,不过这里是作为最小值,因此符号会改变。
在做结点 \(x\) 是,我们设 \(p = \sum\limits_{y \in \text{son}(x)} \max(f(y, 0), f(y, 1))\),并令 \(p\) 为 \(f(x, 0), f(x, 1)\) 的初始值。
那么状态转移方程(\(\leftarrow\) 表示最(大)值操作):
时间复杂度 \(O(n)\)。
「eJOI2018」山
update - 2020.7.27
设 \(f(n, k, 0), f(n, k, 1), f(n, k, 2)\) 表示 \([1, n]\) 中,建造了 \(k\) 座房子,且第 \(n-1\),第 \(n\) 个位置的状态分别为 \((0,0),(1, 0), (0, 1)\) 时(\(0\) 表示没有房子,\(1\) 表示有)的最小花费时间。
状态转移方程:
时间复杂度 \(O(n^2)\)。
「CSP2019-J」纪念品
update - 2020.7.27
直接存物品的个数显然原地升天。但仔细想一下发现,转换成统一在第 \(i\) 天买,然后在第 \(i+1\) 天卖,其实等价。因为即使对某种物品实际上并不操作,换成全卖了然后买回来也未尝不可。
不难设计出一个比较暴力的状态:\(f(i, j, k)\) 表示第 \(i\) 天,对于前 \(j\) 个物品,剩余现金为 \(k\) 时,下一天手头上的最大现金数。转移方程显然。
为了不空间爆炸,我们尝试优化。第一维显然可以缩掉——我们只要上一轮的最优值即可。剩下了两维看着像一个背包,于是倒序以下就只剩最后一维了。方程:
时间复杂度 \(O(TN\times \max P)\)。
「NOIp2018-普及」摆渡车
update - 2020.7.28
\(t\) 数组升序排序,显然的。设 \(f(i, j)\) 表示第 \(i\) 个人等了 \(j\) 分钟,送走前 \(i\) 个人等待总时间的最小值。
直接看 \(j\) 的范围貌似可以达到 \(\max t\),但其实不然——一个人最多等 \(< 2m\) 分钟。
- 相比在起点停着 \(m\) 分钟,啥也不管直接开一趟(尽管空车)总不会更劣,那么停车一次不超过 \(T_1 < m\)。
- 一个人等一辆离开的车回来的时间 \(T_2 \le m\)。
于是一个人等待的时间 \(j = T_1 + T_2 < 2m\)。
那么状态的规模差不多是 \(O(n m)\)。考虑设计转移:
- 若 \(t_i + j \ge t_{i + 1}\),那么第 \(i+1\) 个人赶得上本趟车,则:\(f(i+1, j+t_i-t_{i+1}) \leftarrow f(i,j)+j+t_i-t_{i+1}\)。
- 若 \(t_i+j+m\ge t_{i+1}\),那么第 \(i+1\) 个人可以在车回来前等车,则枚举车回来的时间 \(k\),转移为: \(f(i+1, j+t_i+m+k-t_{i+1}) \leftarrow f(i, j)+j+t_i+m+k-t_{i+1}\)
- 若 \(t_i + j + m < t_{i +1}\),那么第 \(i+1\) 个人在车回到起点后到,则枚举第 \(i+1\) 个人的等待时间 \(k\),转移为: \(f(i+1, k) \leftarrow f(i, j)+k\)。
时间复杂度:\(O(nm^2)\)。
「AHOI2009」中国象棋
update - 2020.7.28
会设状态基本就做完了。设 \(f(i, j, k)\) 表示考虑到第 \(i\) 行,有 \(j\) 列存在一个棋子,\(k\) 列有两个棋子的方案数。
转移非常显然:
- 不放:\(f(i, j, k) \leftarrow f(i-1, j, k)\)。
- 放在空列:
-
- 放一个:\(f(i, j, k) \leftarrow f(i - 1, j - 1, k) \times (m - (j - 1) - k)\)
-
- 放两个:\(f(i, j, k) \leftarrow f(i - 1, j - 2, k) \times C_{m - (j - 2) - k}^2\)
- 放在已经有一个的列:
-
- 放一个:\(f(i, j, k) \leftarrow f(i-1, j+1, k-1) \times (j+1)\)
-
- 放两个:\(f(i, j, k) \leftarrow f(i - 1, j + 2, k - 2)\times C_{j+2}^2\)
- 在已有一个的和空列各放一个:\(f(i, j, k) \leftarrow f(i - 1, j, k - 1)\times j \times (m - j - (k - 1))\)
时间复杂度 \(O(nm^2)\)。
「LA 4394」String painter
update - 2020.7.28
直接算 \(A, B\) 串不好处理,不如先考虑空串到 \(B\) 的步数。设 \(f(i, j)\) 表示从空串到 \(B[i,j]\) 的最小步数。
那么显然有:
我们令答案为 \(g\),\(g(i)\) 表示 \([1, i]\) 部分的答案。那么:
答案为 \(g(n)\),复杂度 \(O(n^3)\)。
「CSP2019-S」Emiya 家今天的饭
update - 2020.7.28
分析题目性质,发现不可能有两列或以上占去一半,不合法的只可能是一列。
那么容斥以下,答案等于 总方案数 减去 某一列不合法的方案数。
合法的方案不难处理:\(g(i, j)\) 表示前 \(i\) 行选了 \(j\) 个的方案数,那么显然 \(g(i, j) = g(i - 1, j) + g(i - 1, j - 1)\times \sum_j a_{i,j}\)。可以在 \(O(n^2)\) 时间内解决。
对于不合法的方案,有一个比较暴力的思路,枚举这个不合法列 \(c\),设 \(f(i, j, k)\) 为前 \(i\) 行,在第 \(c\) 列选了 \(j\) 个,其他列选了 \(k\) 个的方案数。那么有转移:
不合法的总数即为所有 \(\sum_{j>k} f(n, j, k)\) 之和。然而这个需要 \(O(n^3 m)\) 的时间,只有 84 分。
突然发现我们只需要 \(j, k\) 之间的差值大小,并不需要具体大小,于是又砍掉一维—— \(f(i, j)\) 表示当不合法列为 \(c\) 时,考虑到前 \(i\) 行,第 \(c\) 列的个数比其他列多 \(j\) 个的方案数。转移方程:
这样时间复杂度 \(O(n^2m)\)。
「Codeforces 149D」Coloring Brackets
update - 2020.7.29
显然不能直接用 \(f(l, r)\) 表示区间 \([l, r]\) 的方案数,因为相邻位置也有影响。
于是带上 \(l, r\) 的颜色:\(f(l, r, x, y)\) 表示区间 \([l, r]\) 中,位置 \(l\) 颜色为 \(x\),\(r\) 为 \(y\) 的方案数。颜色 \(0/1/2\) 分别表示无色,蓝色,红色。
那么分三种情况讨论:
- \(l + 1 = r\):边界条件,\(f(l, r, 0, 1) = f(l, r, 1, 0) = f(l, r, 0, 2) = f(l, r, 2, 0) = 1\)。
- 位置 \(l, r\) 为一组配对的括号:我们可以由区间 \([l + 1, r - 1]\) 的 dp 值推出,转移显然,根据题意模拟即可。
- 位置 \(l, r\) 为不配对:那么我们可以由两组配对的 dp 值推出。具体地,设位置 \(l\) 的右括号的位置为 \(k\),那么答案就由区间 \([l, k]\) 和 \([k + 1, r]\) 得出。
推荐使用记忆化搜索实现,复杂度 \(O(|s|^2)\)。
「USACO19DEC」Greedy Pie Eaters
update - 2020.7.29
设 \(f(i, j)\) 表示区间 \([i, j]\) 被全部吃完后可得的最大 \(\sum w_i\)。那么有
其中 \(p(i, j, k)\) 表示所有满足 \(i \le l_x\le k\le r_x\le j\) 的 \(k\) 中 \(w_k\) 的最大值。求 \(p\) 数组可以用向外拓展的方式:
在计算 \(p\) 时应先枚举 \(k\)。时间复杂度 \(O(n^3)\)。
「NOIp2018-提高」愤怒的小鸟
update - 2020.7.29
众所周知三点确定一条抛物线。那么设 \(s(i, j)\) 表示点 \((x_i, y_i), (x_j, y_j), (0, 0)\) 构成的抛物线上的点集。显然可以 \(O(n^3)\) 预处理。
设计状态:\(f(S)\) 表示覆盖点集 \(S\) 所需的最小抛物线数。转移:
这个方法是 \(O(T\times 2^n\cdot n^2)\) 的,非常悬。
考虑一个优化:设 \(x\) 为点集 \(S\) 中没有出现过的最小编号的点的编号,即 \(x = \min\{x|\texttt{S&(1<<(x-1))}=0, x\in \mathbb N^+\}\)。那么可以限定由 \(S\) 拓展的转移的线必定经过第 \(x\) 个点。
这相当于限定了顺序,因为原本乱序枚举与现在可以枚举到的范围其实是一样的。时间复杂度 \(O(T\times 2^n\cdot n)\)。
「Codeforces 372C」Watching Fireworks is Fun
update - 2020.7.29
设 \(f(i, j)\) 表示前 \(i\) 个烟花放完后,当前在位置 \(j\) 处,得到的最大快乐值。那么有:
显然这个 dp 是 \(O(n^2m)\) 的,需要优化。
发现这个 \(b\) 可以提出来,那么重新定义 \(f\):
答案即为 \(\sum b_i - \min f(m, j)\)。又发现可以把 \(|a_i-j|\) 提出来,于是我们发现一个类似于 \(f(i)\) 一段滑动区间的最值问题,显然可以单调队列优化。发现 \(k\) 的范围其实有两段,于是正反各做一次, 时间复杂度 \(O(nm)\)。
直接开数组炸空间,于是滚动数组滚掉第一维。
「Codeforces 16E」Fish
update - 2020.7.30
首先要知道 \(x\) 个鱼中任意一对相遇的机率 \(P(x) = \frac{1}{x(x-1)/2}\)。
\(n\) 很小,考虑状压——\(f(S)\) 表示存活下来的鱼的集合为 \(S\) 的概率。转移:
后面的 \(-1\) 改成了 \(+1\) 是因为原本的集合大小为 \(|S| + 1\)。
时间复杂度 \(O(2^n\times n^2)\)。
「POI2014」Little Bird
update - 2020.7.30
设 \(f(i)\) 为到达第 \(i\) 个位置的最小消耗。那么有:
时间复杂度 \(O(qn\sum k_i)\),直接爆炸。
考虑它是一个滑动最值,那么用单调队列优化这个过程。这里的比较关键字有两个:第一为 \(f\) 的大小,第二为 \(d\) 的大小。
优化后复杂度为 \(O(qn)\),STL 的话可能有点卡常。
「POJ 1746」Minimizing maximizer
update - 2020.7.30
有一个比较朴素的想法:\(f(i, j)\) 表示前 \(i\) 个 Sorter 中,位置 \(j\) 到位置 \(1\) 所需 Sorter 数量的最小值。那么有一个非常显然的转移:
但 \(O(nm)\) 的时空复杂度根本无承受。我们发现第一位明显可以缩掉:
然而最坏仍然是 \(O(nm)\) 的,于是使用线段树优化区间最值的过程,得到了 \(O(m\log n)\) 的优秀算法。
「POJ 2836」Rectangular Covering
update - 2020.7.30
首先预处理以所有点对为对顶点的矩形的面积和覆盖点集,分别即为 \(s(i, j), p(i, j)\)。
设 \(f(S)\) 为覆盖点集 \(S\) 所需的最小面积。状态转移方程:
注意共线的特判处理。时间复杂度 \(O(2^n\times n^2)\)。
「POJ 1821」Fence
update - 2020.7.31
先将工人按位置 \(S\) 排序。
设 \(f(i, j)\) 表示前 \(i\) 个工人,处理前 \(j\) 块木板,可得的 \(\sum P_i\) 的最大值。朴素的状态转移:
显然第三个转移是 \(O(n)\) 的,考虑优化。
我们把第三个拆一下:\(f(i, j) = \max\limits_{j - L_i\le k\le S_i - 1} \{f(i-1, k) - P_i\times k\}+P_i\times j\)。
发现中间是一个上界固定为 \(S_i - 1\),下界逐渐上升的区间最值问题。于是单调队列优化。
时间复杂度 \(O(nm)\)。
「HDU 3507」Print Article
update - 2020.7.31
第一道斜率优化 /cy
若令 \(f(i)\) 表示前 \(i\) 个的最小花费。那么有一个显然的转移:
\(O(n^2)\) 的时耗承受不了,考虑优化。
设 \(k<j<i\),若决策 \(j\) 优于 \(k\),那么满足不等式
化简得
我们将 \(j, k\) 抽象成一个二维点 \((x_j, y_j), (x_k, y_k)\),那么设 \(x_t = s(t),y_t = f(t)-s^2(t)\),于是有:
我们使用斜率优化,用单调队列维护这些点,斜率递增。
当做到第 \(i\) 个时,先弹出队首不符合上述不等式的元素,再将队首直接转移至 \(f(i)\),然后将队尾违背斜率单调性的弹出,最后在尾部插入 \(i\)。弹出时须保证队中存在两个及以上的元素。
时间复杂度 \(O(n)\)。
「HNOI2008」玩具装箱
update - 2020.7.31
设前 \(i\) 个的最小花费为 \(f(i)\),则:
为简化计算,设 \(a_t = t + s(t),b_t=t+s(t)+L+1\),于是:
对于某个 \(j\),我们将原转移化为:
设 \(x_t = b_t, y_t = f(t) + b_t^2\),那么这可以被视为一个直线的表达式,为斜率即为 \(2a_i\)。
斜率优化,维护一个斜率递增的单调队列即可,第一个满足斜率 \(\text{slope}(j, j+1) >2a_i\) 的 \(j\) 直接转移。
时间复杂度 \(O(n)\)。
「HDU 2829」Lawrence
update - 2020.8.1
显然的状态:\(f(i, j)\) 表示前 \(i\) 个站点,炸 \(j\) 次产生的最小值。
显然的方程:\(f(i, j) = \min\limits_{k<i} \{ f(k, j - 1) + c(i)-c(k)-s(k)\times (s(i)-s(k)) \}\),其中 \(s(i) = \sum_{j=1}^i a_i, c(i)\) 表示前 \(i\) 个的两两乘积和,\(=c(i-1)+a(i)s(i-1)\)。
单次转移 \(O(n)\),需要优化。设 \(a<b\),且决策 \(a\) 劣于 \(b\),那么有 \(f(a, j-1)-c(a)-s(a)s(i)+s^2(a) > f(b, j-1)-c(b)-s(b)s(i)+s^2(b)\),即:
设 \(x_i = s(i), y_i = f(i, j-1)-c(i)+s^2(i)\),那么带入上式:
于是斜率优化。时间复杂度 \(O(nm)\)。
「THUSC 2016」成绩单
update - 2020.8.1
考虑区间动规,但显然不是 \(f(i, j)\),因为代价与最值有关,而我们这样是无法知道的。
正确的设法应该是,\(f(i, j, l, r)\) 表示区间 \([i, j]\) 消去部分数,剩下数在值域 \([l, r]\) 中的最小花费。
转移?分类讨论:
- \(l = r = 0\)。说明我们需要取完,分为直接取完整个区间,或先取这个区间中某段值域的数字:
- \(l\ne 0\) 或 \(r \ne 0\)。考虑分割这个区间。
-
- 当然如果 \(i=j\) 的话只要判断当前值 \(w_i\) 是否 \(\in [l, r]\) 即可。
-
- 否则枚举断点 \(k\),左右两部分共有 3 中情况:左边取完,右边取完,都不取完:
可以使用记忆化搜索实现,总复杂度 \(O(n^5)\),但由于状态实际并没有这么多,跑不满。
「Codeforces 148D」Bag of mice
update - 2020.8.3
设 \(f(i, j)\) 表示轮到公主时,袋中剩下 \(i\) 只白,\(j\) 只黑,公主胜的概率。
首先 \(f(i, j) \leftarrow \frac{i}{i + j}\),即一下就抓到白的的情况。
两人都抓到黑的,中途跑出一只黑的:
两人都抓到黑的,中途跑出一只白的:
其他败的情况不计算内,复杂度 \(O(w\times b)\)。
「Luogu P1654」OSU!
update - 2020.8.3
考虑这样一个等式:\((x+1)^3 = x^3 + 3x^2 + 3x +1\),相比 \(x^3\) 多出了 \(3x^2 + 3x +1\)。
设 \(f(i)\) 为前 \(i\) 个的期望分数。除此之外,还需维护一次方,二次方的期望值 \(\text{E}(x)\) 和 \(\text{E}(x^2)\)。
对于一、二次方,有:
对于 \(f(i)\) 的计算存在两种情况,当前位置取或不取:
\(O(n)\) 递推即可。
「Luogu P3413」SAC#1 - 萌数
update - 2020.8.3
比较复杂的数位 dp。首先不能直接设 \(f(\text{pos}, \text{isPa}, v_0, v_1)\),而应设为 \(f(\text{pos}, \text{isPa}, ex_0, v_0, ex_1, v_1)\)。其中从左至右分别为当前位置,之前是否已经构成回文,前二位是否有效(若为前导 0 则无效),前二位是什么数字,前一位是否有效,前一位是什么数字。多加了两维是为了防止形如 \(\texttt{000041}\) 这种前导 0 构成回文的实际非法的串混进来。
考虑用记忆化搜索实现。在枚举当前位的数字时,需要多计算一个 bool
值:下一次的回文情况(下一个 \(\text{isPa}\))。
由于数位 dp 的重点根本不在方程而是实现,下面给出搜索部分的代码:
LL f[N][2][2][D][2][D];
LL solve(int pos, bool isPa, bool ex0, int val0, bool ex1, int val1, bool lim, bool zero) {
if (!pos) return LL(isPa);
if (!lim && !zero && (~f[pos][isPa][ex0][val0][ex1][val1]))
return f[pos][isPa][ex0][val0][ex1][val1];
LL ret = 0ll; int maxD = lim ? num[pos] - '0' : 9;
for (int d = 0; d <= maxD; d++) {
bool nxtPa = (val0 == d && ex0) || (val1 == d && ex1) || isPa;
bool nxtZr = zero && (d == 0);
bool nxtLm = lim && (d == maxD);
(ret += solve(pos - 1, nxtPa, ex1, val1, !nxtZr, d, nxtLm, nxtZr)) %= mod;
}
if (!lim && !zero) f[pos][isPa][ex0][val0][ex1][val1] = ret;
return ret;
}
「SDOI2016」征途
update - 2020.8.4
首先推式子,化简方差:\(v = \dfrac{1}{m}\sum\limits_{i=1}^m v_i^2 - \dfrac{1}{m^2}\left(\sum\limits_{i=1}^m v_i\right)^2\),那么 \(v\times m^2 = m\sum\limits_{i=1}^m v_i^2 - \left(\sum\limits_{i=1}^m v_i\right)^2\)。
这个式子的第二项显然不变,着重考虑第一项中的平方和部分。
设 \(f(t, i)\) 表示走了 \(t\) 段到位置 \(i\) 的最小平方和。那么朴素的转移:
这个 \(O(n)\) 一次的转移显然可以斜率优化。
具体的,我们设 \(a < b\) 且 \(a\) 劣于 \(b\),那么:
然后用单调队列维护一个斜率递增的下凸包即可。复杂度 \(O(nm)\)。
「Luogu P1613」跑路
update - 2020.8.4
这是一个最短路问题,但真正的图并不是原图。我们设 \(f(u, v)\) 为结点 \(u, v\) 的联通情况,现在需要处理出这个图。
看到 \(2^k\) 就很显然是倍增。设 \(g(u, v, t)\) 为是否存在连接 \(u, v\) 长度为 \(2^t\) 的路径。那么可以用 dp 的方法处理出来:
对于 \(f(i, j)\) 的值,若存在一个 \(t\in[0, \log_2(\text{maxlongint})]\),使得 \(g(i, j, k)=\texttt{true}\),那么 \(f(i, j) = 1\),反之则为 \(\infty\)。
最后在 \(f\) 上跑 Floyd 即可。时间复杂度 \(O(n^3 \log m)\)。
来源:oschina
链接:https://my.oschina.net/u/4289967/blog/4470138