Loading docs/dp/optimization.md +114 −3 Original line number Diff line number Diff line Loading @@ -2,9 +2,120 @@ By [hsfzLZH1](https://github.com/hsfzLZH1) 本章主要讲解动态规划的几种基础 ** 优化 ** 方法。 ## 单调队列优化 ## 四边形不等式优化 学习本章前,请务必先学习 [单调队列](https://oi-wiki.org/ds/monotonous-queue/)。 ### 例题 [luogu P1880 [NOI1995]石子合并](https://www.luogu.org/problemnew/show/P1880) 题目大意:在一个环上有 $n$ 个数,进行 $n-1$ 次合并操作,每次操作将相邻的两堆合并成一堆,能获得新的一堆中的石子数量的和的得分。你需要最大化你的得分。 我们首先 ** 破环成链 ** ,然后进行动态规划。设 $f_{i,j}$ 表示从位置 $i$ 合并到位置 $j$ 所能得到的最大得分, $sum_i$ 为前 $i$ 堆石子数的前缀和。 写出 ** 状态转移方程 **: $f_{i,j}=max{f_{i,k}+f_{k+1,j}+(sum_j-sum_i)}(i\le k\le j)$ 考虑常规的转移方法,枚举 $i$ , $j$ 和 $k$ ,时间复杂度为 $O(n^3)$。 ### 什么是四边形不等式? 对于 $a<b\le c<d$,如果有$f_{a,c}+f_{b,d}\le f_{b,c}+f_{a,d}$,则称该数组满足四边形不等式,可以用通俗的方法表述为“交叉小于包含”。 两个定理: 1.四边形不等式能优化的状态转移方程能表示为 $f_{i,j}=max{f_{i,k}+f_{k+1,j}+cost(i,j)}(i\le k\le j)$。如果 $cost$ 函数同时满足单调性和四边形不等式,那么数组 $f$ 也满足四边形不等式。 定义 $idx_{i,j}$ 为在转移 $f_{i,j}$ 的过程中在 $k=idx_{i,j}$ 时取得最小值,那么有如下定理: 2.如果 $f$ 数组满足四边形不等式,那么 $idx$ 函数满足单调性,即有 $idx_{i,j}\le idx_{i,j+1}\le idx_{i+1,j+1}$ 。 证明会和题目解法一起 $qwq$ ### 回到题目 第一步:证明 $cost$ 满足四边形不等式 要证明,对于所有满足 $i<i+1\le j<j+1$ 的 $i,j$ , 均有 $cost_{i,j}+cost_{i+1,j+1}\le cost_{i+1,j}+cost_{i,j+1}$。 移项得 $cost_{i,j}-cost_{i+1,j}\le cost_{i,j+1}-cost_{i+1,j+1}$ 设 $F(j)=cost_{i,j}-cost{i+1,j}$ ,如果要使这个四边形不等式成立,那么就要证明 $F(j)$ 单调非降。 在本题中, $F(j)=(sum_j-sum_{i-1})-(sum_j-sum_i)=sum_i-sum_{i-1}=a_i$ ,与 $j$ 无关,自然一定满足四边形不等式。 证毕。 第二步:证明 $f$ 满足四边形不等式 同样的,应有如下结论:对于所有满足 $i<i+1\le j<j+1$ 的 $i,j$ , 均有 $f_{i,j}+f_{i+1,j+1}\le f_{i+1,j}+f_{i,j+1}$ 我们假设 $x=idx_{i+1,j},y=idx_{i,j+1}$。不妨设 $x<=y$。 将 $x,y$ 带入得, $f_{i,j}+f_{i+1,j+1}=f_{i,x}+f_{x+1,j}+cost_{i,j}+f_{i+1,y}+f_{y+1,j+1}+cost_{i+1,j+1}$ 由于上一步已经证明出了$cost$满足四边形不等式,而该不等式的左边在上式出现过,将其替换得 $f_{i,x}+f_{x+1,j}+cost_{i,j}+f_{i+1,y}+f_{y+1,j+1}+cost_{i+1,j+1}\le f_{i,x}+f_{x+1,j+1}+cost{i,j+1}+f_{i+1,y}+f_{y+1,j}+cost_{i+1,j}$ 消去公共项可得 $f_{i,j}+f_{i+1,j+1}\le f_{i+1,j}+f_{i,j+1}$ 证毕。 第三步:证明决策的单调性 现在我们已经证明了 $cost$ 和 $f$ 满足四边形不等式,要证明决策的单调性以证明优化的正确性。 即证 $idx_{i,j-1}\le idx_{i,j}\le idx_{i+1,j}$ 我们只证明式子的前半部分,后半部分可以有类似的方法推出。 设 $y=idx_{i,j-1},x\le y$ ,因为 $x+1\le y+1\le j-1<j$,由四边形不等式可得, $f_{x+1,j-1}+f_{y+1,j}\le f_{y+1,j-1}+f_{x+1,j}$ 由于我们是令 $y=idx_{i,j-1},x\le y$ 时 $f_{i,j-1}$ 取得最小值,那么 $f_{i,j-1}(idx_{i,j-1}=x)$ 一定大于等于 $dp[i][j-1](idx_{i,j-1}=y)$ ,所以对于 $f_{i,j-1}$ 可以取到最优值的 $y$ ,所有小于它的值,对于 $f_{i,j}$ 来说,都没有 $y$ 优,所以最优决策一定不是小于$y$ 的,那么一定有 $idx_{i,j-1}\le idx_{i,j}$ 证毕。 ### 说了这么多,怎么进行状态转移呢? 给出核心代码: ```cpp for(int i=n;i>=1;i--) { for(int j=i+1;j<=n;j++) { f[i][j]=inf; for(int k=s[i][j-1];k<=s[i+1][j];k++) { if(f[i][j]<f[i][k]+f[k+1][j]+sum[j]-sum[i-1]) { f[i][j]=f[i][k]+f[k+1][j]+sum[j]-sum[i-1]; idx[i][j]=k; } } } } ``` 注意:由于在计算 $f_{i,j}$ 的时候需要知道 $s_{i,j-1}$ 和 $s_{i+1,j}$ 的值,所以 $i$ 的循环逆序。 ### 时间复杂度证明 计算 $f_{i,j}$ 时,我们要循环 $s_{i+1,j}-s_{i,j-1}$ 次,那么一共加起来会循环多少次呢? 因为 $\sum_{i=1}^{n-1}(idx_{i+1,i+1}-idx_{i,i})=idx{n,n}-idx{1,1}$ 很显然和 $n$ 同阶,那么它的 $n$ 倍就和 $n^2$ 同阶,时间复杂度是 $O(n^2)$。 ### 几道练习题 [luogu P4767 [IOI2000]邮局](https://www.luogu.org/problemnew/show/P4767) ### 参考资料 [NOIAu 的CSDN 博客](https://blog.csdn.net/noiau/article/details/72514812) ## 单调队列&单调栈优化 学习本节前,请务必先学习 [单调队列](https://oi-wiki.org/ds/monotonous-queue/)。 ### 例题 [CF372C Watching Fireworks is Fun](http://codeforces.com/problemset/problem/372/C) Loading Loading @@ -33,7 +144,7 @@ $f_{i,j}=max\{f_{i-1,k}+b_i+|a_i-j|\}=max\{f_{i-1,k}+|a_i-j|\}+b_i$ 讲完了,让我们归纳一下单调队列优化动态规划问题的基本形态:当前状态的所有值可以从上一个状态的某个连续的段的值得到,要对这个连续的段进行 RMQ 操作,相邻状态的段的左右区间满足非降的关系。 几道练习题(按笔者所认为的难度排序,仅供参考): ### 几道练习题: [luogu P1886 滑动窗口](https://www.luogu.org/problemnew/show/P1886) Loading Loading
docs/dp/optimization.md +114 −3 Original line number Diff line number Diff line Loading @@ -2,9 +2,120 @@ By [hsfzLZH1](https://github.com/hsfzLZH1) 本章主要讲解动态规划的几种基础 ** 优化 ** 方法。 ## 单调队列优化 ## 四边形不等式优化 学习本章前,请务必先学习 [单调队列](https://oi-wiki.org/ds/monotonous-queue/)。 ### 例题 [luogu P1880 [NOI1995]石子合并](https://www.luogu.org/problemnew/show/P1880) 题目大意:在一个环上有 $n$ 个数,进行 $n-1$ 次合并操作,每次操作将相邻的两堆合并成一堆,能获得新的一堆中的石子数量的和的得分。你需要最大化你的得分。 我们首先 ** 破环成链 ** ,然后进行动态规划。设 $f_{i,j}$ 表示从位置 $i$ 合并到位置 $j$ 所能得到的最大得分, $sum_i$ 为前 $i$ 堆石子数的前缀和。 写出 ** 状态转移方程 **: $f_{i,j}=max{f_{i,k}+f_{k+1,j}+(sum_j-sum_i)}(i\le k\le j)$ 考虑常规的转移方法,枚举 $i$ , $j$ 和 $k$ ,时间复杂度为 $O(n^3)$。 ### 什么是四边形不等式? 对于 $a<b\le c<d$,如果有$f_{a,c}+f_{b,d}\le f_{b,c}+f_{a,d}$,则称该数组满足四边形不等式,可以用通俗的方法表述为“交叉小于包含”。 两个定理: 1.四边形不等式能优化的状态转移方程能表示为 $f_{i,j}=max{f_{i,k}+f_{k+1,j}+cost(i,j)}(i\le k\le j)$。如果 $cost$ 函数同时满足单调性和四边形不等式,那么数组 $f$ 也满足四边形不等式。 定义 $idx_{i,j}$ 为在转移 $f_{i,j}$ 的过程中在 $k=idx_{i,j}$ 时取得最小值,那么有如下定理: 2.如果 $f$ 数组满足四边形不等式,那么 $idx$ 函数满足单调性,即有 $idx_{i,j}\le idx_{i,j+1}\le idx_{i+1,j+1}$ 。 证明会和题目解法一起 $qwq$ ### 回到题目 第一步:证明 $cost$ 满足四边形不等式 要证明,对于所有满足 $i<i+1\le j<j+1$ 的 $i,j$ , 均有 $cost_{i,j}+cost_{i+1,j+1}\le cost_{i+1,j}+cost_{i,j+1}$。 移项得 $cost_{i,j}-cost_{i+1,j}\le cost_{i,j+1}-cost_{i+1,j+1}$ 设 $F(j)=cost_{i,j}-cost{i+1,j}$ ,如果要使这个四边形不等式成立,那么就要证明 $F(j)$ 单调非降。 在本题中, $F(j)=(sum_j-sum_{i-1})-(sum_j-sum_i)=sum_i-sum_{i-1}=a_i$ ,与 $j$ 无关,自然一定满足四边形不等式。 证毕。 第二步:证明 $f$ 满足四边形不等式 同样的,应有如下结论:对于所有满足 $i<i+1\le j<j+1$ 的 $i,j$ , 均有 $f_{i,j}+f_{i+1,j+1}\le f_{i+1,j}+f_{i,j+1}$ 我们假设 $x=idx_{i+1,j},y=idx_{i,j+1}$。不妨设 $x<=y$。 将 $x,y$ 带入得, $f_{i,j}+f_{i+1,j+1}=f_{i,x}+f_{x+1,j}+cost_{i,j}+f_{i+1,y}+f_{y+1,j+1}+cost_{i+1,j+1}$ 由于上一步已经证明出了$cost$满足四边形不等式,而该不等式的左边在上式出现过,将其替换得 $f_{i,x}+f_{x+1,j}+cost_{i,j}+f_{i+1,y}+f_{y+1,j+1}+cost_{i+1,j+1}\le f_{i,x}+f_{x+1,j+1}+cost{i,j+1}+f_{i+1,y}+f_{y+1,j}+cost_{i+1,j}$ 消去公共项可得 $f_{i,j}+f_{i+1,j+1}\le f_{i+1,j}+f_{i,j+1}$ 证毕。 第三步:证明决策的单调性 现在我们已经证明了 $cost$ 和 $f$ 满足四边形不等式,要证明决策的单调性以证明优化的正确性。 即证 $idx_{i,j-1}\le idx_{i,j}\le idx_{i+1,j}$ 我们只证明式子的前半部分,后半部分可以有类似的方法推出。 设 $y=idx_{i,j-1},x\le y$ ,因为 $x+1\le y+1\le j-1<j$,由四边形不等式可得, $f_{x+1,j-1}+f_{y+1,j}\le f_{y+1,j-1}+f_{x+1,j}$ 由于我们是令 $y=idx_{i,j-1},x\le y$ 时 $f_{i,j-1}$ 取得最小值,那么 $f_{i,j-1}(idx_{i,j-1}=x)$ 一定大于等于 $dp[i][j-1](idx_{i,j-1}=y)$ ,所以对于 $f_{i,j-1}$ 可以取到最优值的 $y$ ,所有小于它的值,对于 $f_{i,j}$ 来说,都没有 $y$ 优,所以最优决策一定不是小于$y$ 的,那么一定有 $idx_{i,j-1}\le idx_{i,j}$ 证毕。 ### 说了这么多,怎么进行状态转移呢? 给出核心代码: ```cpp for(int i=n;i>=1;i--) { for(int j=i+1;j<=n;j++) { f[i][j]=inf; for(int k=s[i][j-1];k<=s[i+1][j];k++) { if(f[i][j]<f[i][k]+f[k+1][j]+sum[j]-sum[i-1]) { f[i][j]=f[i][k]+f[k+1][j]+sum[j]-sum[i-1]; idx[i][j]=k; } } } } ``` 注意:由于在计算 $f_{i,j}$ 的时候需要知道 $s_{i,j-1}$ 和 $s_{i+1,j}$ 的值,所以 $i$ 的循环逆序。 ### 时间复杂度证明 计算 $f_{i,j}$ 时,我们要循环 $s_{i+1,j}-s_{i,j-1}$ 次,那么一共加起来会循环多少次呢? 因为 $\sum_{i=1}^{n-1}(idx_{i+1,i+1}-idx_{i,i})=idx{n,n}-idx{1,1}$ 很显然和 $n$ 同阶,那么它的 $n$ 倍就和 $n^2$ 同阶,时间复杂度是 $O(n^2)$。 ### 几道练习题 [luogu P4767 [IOI2000]邮局](https://www.luogu.org/problemnew/show/P4767) ### 参考资料 [NOIAu 的CSDN 博客](https://blog.csdn.net/noiau/article/details/72514812) ## 单调队列&单调栈优化 学习本节前,请务必先学习 [单调队列](https://oi-wiki.org/ds/monotonous-queue/)。 ### 例题 [CF372C Watching Fireworks is Fun](http://codeforces.com/problemset/problem/372/C) Loading Loading @@ -33,7 +144,7 @@ $f_{i,j}=max\{f_{i-1,k}+b_i+|a_i-j|\}=max\{f_{i-1,k}+|a_i-j|\}+b_i$ 讲完了,让我们归纳一下单调队列优化动态规划问题的基本形态:当前状态的所有值可以从上一个状态的某个连续的段的值得到,要对这个连续的段进行 RMQ 操作,相邻状态的段的左右区间满足非降的关系。 几道练习题(按笔者所认为的难度排序,仅供参考): ### 几道练习题: [luogu P1886 滑动窗口](https://www.luogu.org/problemnew/show/P1886) Loading