# 【学习笔记】动态规划—各种 $DP$ 优化 [原文链接,致敬大神](https://www.cnblogs.com/Xing-Ling/p/11317315.html) ## 【大前言】 个人认为贪心,$dp$ 是最难的,每次遇到题完全不知道该怎么办,看了题解后又瞬间恍然大悟(TAT)。这篇文章也是花了我差不多一个月时间才全部完成。 ## 【进入正题】 用动态规划解决问题具有 **空间耗费大**、 **时间效率高** 的特点,但也会有时间效率不能满足要求的时候,如果算法有可以优化的余地,就可以考虑时间效率的优化。 ## 【$DP$ 时间复杂度的分析】 $DP$ 高时间效率的关键在于它减少了 **冗余** ,即不必要的计算或重复计算部分,算法的冗余程度是决定算法效率的关键。而动态规划就是在将问题规模不断缩小的同时,记录已经求解过的子问题的解,充分利用求解结果,避免了反复求解同一子问题的现象,从而减少 **冗余** 但是,一个动态规划问题很难做到完全消除 **冗余** 下面给出动态规划时间复杂度的决定因素: ### 时间复杂度 = 状态总数 × 每个状态转移的状态数 × 每次状态转移的时间 ## 【$DP$ 优化思路】 ### 一:减少状态总数 (1). 改进状态表示 (2). 选择适当的规划方向 ### 二:减少每个状态转移的状态数 (1). 四边形不等式和决策的单调性 (2). 决策量的优化 (3). 合理组织状态 (4). 细化状态转移 ### 三:减少状态转移的时间 (1). 减少决策时间 (2). 减少计算递推式的时间 (上述内容摘自 《动态规划算法的优化技巧》毛子青 ,想要深入了解其思想的可以去看看这篇写得 **超级好** 的论文。) 看到这里是不是已经感觉有点蒙了呢? 本蒟蒻总结了一个简化版本: ## 【$DP$ 三要点】 在推导 $dp$ 方程时,我们时常会感到毫无头绪,而实际上 $dp$ 方程也是有迹可循的,总的来说,需要关注两个要点:**状态**,**决策和转移**。其中 **状态最为关键**, **决策最为复杂**。 ### 【状态】 关于 **状态** 的优化可以从很多角度出发,思维难度极其高,有时候状态选择的好坏会直接导致出现 **爆零** 和 **满分** 的分化。 ### 【决策】 与 **状态** 不同,**决策** 优化则有着大量模板化的东西,在各大书籍,文章上你都可以看到这样的话:只要是形如 $XXX$ 的状态转移方程,都可以用 $XXX$ 进行优化。 ### 【转移】 **转移** 则指由最优决策点得到答案的转移过程,其复杂度一般较低,通常可以忽略,但有时也需要特别注意并作优化。 本文将会重点针对 **决策** 优化部分作一些总结,记录自己的感悟和理解。 $$QAQ$$ # 一:【矩阵优化 $DP$】 $updata$ 之后由于篇幅过大,已搬出。。。。。 [【学习笔记】动态规划—矩阵递推加速](https://www.cnblogs.com/Xing-Ling/p/11594147.html) TODO 挖坑待填 补充:其实质是优化 **转移**。 $$QAQ$$ # 二:【数据结构优化 $DP$】 ## 【前言】 在一些 $dp$ 方程的状态转移过程中,我们通常需要在某个范围内进行择优,选出最佳决策点,这往往可以作为 $dp$ 优化的突破口。 数据结构的使用较灵活,没有一个特定的模板,需要根据具体情况而定,选择合适的方案。由于状态转移总是伴随着 **区间查询最值**,**区间求和** 等操作,即 **动态区间操作**,所以 **平衡树** 可以作为一个有用的工具,但考虑到代码复杂度,使用 **树状数组** 或者 **线段树** 将会是一个不错的选择。 其实质是优化 **决策**。 ## 1.【维护合适的信息】 以 [$The$ $Battle$ $of$ $Chibi$ [$UVA12983$]](https://www.luogu.com.cn/problem/UVA12983) 为例,大概题意就是计算在给定的序列中严格单调递增子序列的数量,并对 $1e9+7$ 取模,给定序列长度小于等于 $1000$ 。 方程应该是比较好推的,用 $dp[i][j]$ 表示由序列中在 $j$ 之前的数构成并以 $a[j]$ 结尾的子序列中,长度为 $i$ 的子序列的数量。则: $$\large dp[i][j]=\sum dp[i−1][k]$$ ,其中 $k $Q:$状态用一维表示行不行? $A$:如果是一维表示,那么就是表示由序列中在 $j$ 之前的数构成并以 $a[j]$ 结尾的子序列的数量。这时考虑一下状态转移,看看它的前序状态是怎么样转移过来的:枚举它前面所有的数字,$a[k] 不行,比如$1~ 2~ 2~ 2~ 6 ~ 3~ 3~ 4$,因为存在重复数字$2$,会造成统计重复,无法去重。 > 办法就是增加一个维度,还要记录以$k$结尾时的子序列长度,就解决了去重的问题。 对于决策点 $dp[i−1][k]$ 这里出现了 $3$ 个信息: 1. 在原序列中的位置 $k