Loading docs/dp/optimizations/state-optimization.md 0 → 100644 +64 −0 Original line number Diff line number Diff line ## 概述 优化 dp 时,不止可以从转移过程入手,加速转移。有时,也可以从状态定义入手,通过改变设计状态的方式实现复杂度上的优化。 令人比较头疼的是,这类优化大多不具有通用性,即不能很套路地应用于多个题目中。因此,下文将从具体例题出发,力求提供思路上的启发,希望可以对读者有一定帮助。 ## Example I ### Problem 给定两个长度分别为 $n,m$ 且仅由小写字母构成的字符串 $A,B$,求 $A,B$ 的最长公共子序列。$(n\le 1e6,m\le 1e3)$ ### Naive solution 您一眼秒了它,这不是板子吗? 定义状态 $dp[i][j]$ 为 $A$ 的前 $i$ 位与 $B$ 的前 $j$ 位最长公共子串,则有 $$ dp[i][j]=\begin{cases}\max(dp[i-1][j],dp[i][j-1])\;\;(A[i]\;!=B[j])\\dp[i-1][j-1]+1\;\;(A[i]==B[j]\end{cases} $$ 好简单,送分的吧。。。 恭喜,您退役了~ 上述做法的时间复杂度 $O(nm)$,无法通过本题。 ### Higher solution 我们仔细一想,发现了一个性质:最终答案不会超过 $m$。 我们又仔细一想,发现 LCS 满足贪心的性质。 更改状态定义 $dp[i][j]$ 为与 $B$ 前 $i$ 位的最长公共子序列长度为 $j$ 的 $A$ 的最短前缀长度(即将朴素做法的答案与第一维状态对调) 可以通过预处理 $A$ 的每一位的下一个 $a,b,\cdots,z$ 的出现位置进行 $O(1)$ 的顺推转移。 复杂度 $O(m^2+26\times n)$,可以通过本题。 ## Example II ### Problem 给定一个 $N$ 个点的无权有向图,判断该图是否存在哈密顿回路。$(2\le N\le 20)$ ### Naive solution 看到数据范围,我们考虑状压。 设 $dp[st][i]$ 表示从 $1$ 出发,经过点集 $st$ 后到达 $i$ 的方案是否存在。则有 $$ dp[st][i]=\sum dp[st-2^{i-1}][j]\&mp[j][i]\;\;(st\&2^{i-1} \;\&\&\; st\&2^{j-1}) $$ 其中$mp$为图的邻接矩阵 时间复杂度 $O(n^2 \times 2^n)$,写得好看或许能过,但是并不优美。 ### Higher solution 上面的状态设计中,每个 dp 值只代表一个 bool 值,这让我们觉得有些浪费。 我们可以考虑对于每个状态 $st$ 将 $dp[st][1 \cdots n]$ 压成一个 int ,发现我们可以将邻接矩阵同样压缩后进行 $O(1)$ 转移。 时间复杂度 $O(n\times 2^n)$ ,可以稳过这道题。 mkdocs.yml +1 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ nav: - 单调队列/单调栈优化: dp/optimizations/monotonous-queue-stack.md - 斜率优化: dp/optimizations/convex-hull-optimization.md - 四边形不等式优化: dp/optimizations/knuth-yao-quadrangle-inequality.md - 状态设计优化: dp/optimizations/state-optimization.md - 其它 DP 方法: dp/misc.md - 字符串: - 字符串部分简介: string/index.md Loading Loading
docs/dp/optimizations/state-optimization.md 0 → 100644 +64 −0 Original line number Diff line number Diff line ## 概述 优化 dp 时,不止可以从转移过程入手,加速转移。有时,也可以从状态定义入手,通过改变设计状态的方式实现复杂度上的优化。 令人比较头疼的是,这类优化大多不具有通用性,即不能很套路地应用于多个题目中。因此,下文将从具体例题出发,力求提供思路上的启发,希望可以对读者有一定帮助。 ## Example I ### Problem 给定两个长度分别为 $n,m$ 且仅由小写字母构成的字符串 $A,B$,求 $A,B$ 的最长公共子序列。$(n\le 1e6,m\le 1e3)$ ### Naive solution 您一眼秒了它,这不是板子吗? 定义状态 $dp[i][j]$ 为 $A$ 的前 $i$ 位与 $B$ 的前 $j$ 位最长公共子串,则有 $$ dp[i][j]=\begin{cases}\max(dp[i-1][j],dp[i][j-1])\;\;(A[i]\;!=B[j])\\dp[i-1][j-1]+1\;\;(A[i]==B[j]\end{cases} $$ 好简单,送分的吧。。。 恭喜,您退役了~ 上述做法的时间复杂度 $O(nm)$,无法通过本题。 ### Higher solution 我们仔细一想,发现了一个性质:最终答案不会超过 $m$。 我们又仔细一想,发现 LCS 满足贪心的性质。 更改状态定义 $dp[i][j]$ 为与 $B$ 前 $i$ 位的最长公共子序列长度为 $j$ 的 $A$ 的最短前缀长度(即将朴素做法的答案与第一维状态对调) 可以通过预处理 $A$ 的每一位的下一个 $a,b,\cdots,z$ 的出现位置进行 $O(1)$ 的顺推转移。 复杂度 $O(m^2+26\times n)$,可以通过本题。 ## Example II ### Problem 给定一个 $N$ 个点的无权有向图,判断该图是否存在哈密顿回路。$(2\le N\le 20)$ ### Naive solution 看到数据范围,我们考虑状压。 设 $dp[st][i]$ 表示从 $1$ 出发,经过点集 $st$ 后到达 $i$ 的方案是否存在。则有 $$ dp[st][i]=\sum dp[st-2^{i-1}][j]\&mp[j][i]\;\;(st\&2^{i-1} \;\&\&\; st\&2^{j-1}) $$ 其中$mp$为图的邻接矩阵 时间复杂度 $O(n^2 \times 2^n)$,写得好看或许能过,但是并不优美。 ### Higher solution 上面的状态设计中,每个 dp 值只代表一个 bool 值,这让我们觉得有些浪费。 我们可以考虑对于每个状态 $st$ 将 $dp[st][1 \cdots n]$ 压成一个 int ,发现我们可以将邻接矩阵同样压缩后进行 $O(1)$ 转移。 时间复杂度 $O(n\times 2^n)$ ,可以稳过这道题。
mkdocs.yml +1 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ nav: - 单调队列/单调栈优化: dp/optimizations/monotonous-queue-stack.md - 斜率优化: dp/optimizations/convex-hull-optimization.md - 四边形不等式优化: dp/optimizations/knuth-yao-quadrangle-inequality.md - 状态设计优化: dp/optimizations/state-optimization.md - 其它 DP 方法: dp/misc.md - 字符串: - 字符串部分简介: string/index.md Loading