This commit is contained in:
HuangHai
2025-08-30 18:35:01 +08:00
commit 1f397eca87
6258 changed files with 1487241 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
2
3 2
1 2 3
3 2
3 2 1

View File

@@ -0,0 +1,17 @@
# $UVA12983$ $The$ $Battle$ $of$ $Chibi$
[题目传送门](https://www.luogu.com.cn/problem/UVA12983)
#### 离散+$dp$动规+树状数组优化
**状态表示**
$dp[i][j]$ 表示以第 $i$ 个数结尾,长度为 $j$ 的 **严格上升子序列** 的个数
**状态转移**
$$\large dp[i][j]=\sum_{k=1,a_k<a_i}^{i-1} dp[k][j-1]$$​
TODO 挖坑待填
现在还没有复习树状数组、线段树等知识,等复习后,第三轮复习DP斜率优化时,再综合树状数组的知识对此详细理解,撰写题解。
2022-9-30

View File

@@ -0,0 +1,2 @@
Case #1: 3
Case #2: 0

View File

@@ -0,0 +1,53 @@
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7; //取模
const int N = 1010;
const int M = 1010;
int n; //原序列长度
int m; //目标序列长度
int f[N][M];
int a[N];
// 原题链接 https://www.luogu.com.cn/problem/solution/UVA12983
int main() {
//加快读入
cin.tie(0), ios::sync_with_stdio(false);
//文件输入
freopen("UVA12983.in", "r", stdin);
//文件输出
// freopen("UVA12983.out", "w", stdout);
int T;
//测试数据组数
cin >> T;
for (int Case = 1; Case <= T; Case++) { // while(T--) ,由于要输出 Case +数字,所以写成for,为了怕占用i,j变量,起名为idx
cin >> n >> m; //由n个数字中挑选,最终严格上升子序列的个数为m 个
int sum = 0; //结果为累加和,因为最终长度为m,可以从m,m+1,m+2,...,n个数字中选择,最终长度为m即可
// DP初始化
memset(f, 0, sizeof(f)); // f[i][j]表示 在前i个数字中选择,并且,是后一位是i的,并且长度是j的 子序列 个数
//个数的初始值
//这个初始值有意思:不管给我几个数字,最终生成的是位的子序列,那么,只有一种可能
for (int i = 1; i <= n; i++) f[i][1] = 1;
for (int i = 1; i <= n; i++) cin >> a[i]; //读入原序列
//开始O(N^3)级的DP
//小的数量在外层循环,大的数量在内层循环,这会影响很大的运算速率
for (int j = 2; j <= m; j++) // 小数在外层循环;j=1的已经根据实际意义给上了初始值1,从2开始递推
for (int i = j; i <= n; i++) // 大数在内层循环
for (int k = 1; k < i; k++) // 遍历所有前序可能
if (a[k] < a[i]) // 保证严格递增
f[i][j] = (f[k][j - 1] + f[i][j]) % mod; // 不断累加,不断取模
for (int i = m; i <= n; i++) sum += f[i][m]; //在m确定的情况下,每个一个m~n之间的原始长度都包含解
cout << "Case #" << Case << ": " << sum << endl;
}
return 0;
}

View File

@@ -0,0 +1,107 @@
# 【学习笔记】动态规划—各种 $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<j$ 且 $a[k]<a[j]$ 。
> $Q:$状态用一维表示行不行?
$A$:如果是一维表示,那么就是表示由序列中在 $j$ 之前的数构成并以 $a[j]$ 结尾的子序列的数量。这时考虑一下状态转移,看看它的前序状态是怎么样转移过来的:枚举它前面所有的数字,$a[k]<a[j]$,这样不行吗?
> 不行,比如$1~ 2~ 2~ 2~ 6 ~ 3~ 3~ 4$,因为存在重复数字$2$,会造成统计重复,无法去重。
> 办法就是增加一个维度,还要记录以$k$结尾时的子序列长度,就解决了去重的问题。
对于决策点 $dp[i−1][k]$ 这里出现了 $3$ 个信息:
1. 在原序列中的位置 $k<j$ 。
2. $a[k]<a[j]$ 。
3. $dp[i−1][k]$ 的和。

View File

@@ -0,0 +1,211 @@
## 【学习笔记】动态规划—斜率优化$DP$
[原文链接,致敬大神](https://www.cnblogs.com/Xing-Ling/p/11210179.html)
https://www.jianshu.com/p/72387491a758
https://blog.csdn.net/tanjunming2020/article/details/126977257
### 【前言】
第一次写这么长的文章。
写完后对 **斜优** 的理解又加深了不少($update$ $2020$.$6$.$19$: 回过头来看这句话满是讽刺啊,明明这时候连 **基本的概念** 都 **没有理清** ....)。
本文讲解较详,只要耐心读下去,相信大部分 $OIer$ 都能看懂。
**斜率优化** $dp$,顾名思义就是利用 **斜率相关性质** 对 $dp$ 进行优化。
**斜率优化** 通常可以 **由两种方式来理解** ,需要灵活地运用数学上的 **数形结合**, **线性规划** 思想。
按照正常思路列出$DP$方程后,如发现其形如$$\large dp[i]=Min/Max(dp[j]+v[j]\times w[i])$$的形式,即可使用斜率优化$DP$。($v[j]$和$w[i]$分别表示两个关于$j$和$i$的函数)
该方程的关键点在于 $v[j] \times w[i]$ 这一项,它既有 $i$ 又有 $j$,于是 **单调队列优化** **不再适用**,可以 **尝试** 使用 **斜率优化**。
### 一.【理解方式】
以 [【模板】 玩具装箱 $toy$ [$P3195$]](https://www.luogu.com.cn/problem/P3195) 为例,两种斜优的理解方式。
设 $\large \displaystyle S[n]=\sum_{i=1}^n(C[i]+1)$,用 $dp[i]$ 表示装好前 $i$ 个的最小花费,则转移方程为:
$$\large dp[i]=min(dp[j]+(S[i]−S[j]−1−L)^2)$$
<font color='red' size=4><b>注:两件玩具之间要加入一个单位长度的填充物,$j+1 \sim i$的话,最后一个$i$里没有这个一个单位长度,需要减去$1$。</b></font>
为方便描述,**将 $L$ 提前加 $1$**,再把 $min$ **去掉**,得到状态转移方程:
$$\large dp[i]=dp[j]+(S[i]−S[j]−L)^2$$
化简得:
$$\large dp[i]=S[i]^2−2S[i]L+dp[j]+(S[j]+L)^2−2S[i]S[j]$$
#### 1.【代数法(数形结合)】
只含 $L$ 的项对于每一个 $i$ 的 **择优筛选** 过程都是完全一样的值,只含 $Function(i)$ 的项在一次 $i$ 的**择优筛选**过程中不变,含 $Function(j)$ 的项可能会不断变化(在本题中表现为为**严格单增**)。
我们以此为划分依据,把同类型的项用括号括起来,即:
$$\large dp[i]=(−2S[i]S[j])+(dp[j]+(S[j]+L)^2)+(S[i]^2−2S[i]L)$$
##### (1).【维护一个凸包】
设 $j_1,j_2 (0⩽j_1<j_2<i)$ 为 $i$ 的两个决策点,且满足**决策点** $j_2$ 优于 $j_1$,
有: $$\large (−2S[i]S[j_2])+(dp[j_2]+(S[j_2]+L)^2)+(S[i]^2−2S[i]L)⩽(−2S[i]S[j_1])+(dp[j_1]+(S[j_1]+L)^2)+(S[i]^2−2S[i]L) \\
\Rightarrow \\
\large (−2S[i]S[j_2])+(dp[j_2]+(S[j_2]+L)^2)⩽(−2S[i]S[j_1])+(dp[j_1]+(S[j_1]+L)^2)$$
**划重点**:此处**移项**需要遵循的原则是:**参变分离**。将 $Function(i)$ 视作未知量,用 $Function(j)$ 来表示出 $Function(i)$ 。
移项得:$\large −2S[i](S[j_2]−S[j_1])⩽(dp[j_1]+(S[j_1]+L)^2)−(dp[j_2]+(S[j_2]+L)^2)$
$∵C[j]⩾1$
$∴S[j+1]>S[j]$
又$∵j_2>j_1$
$∴S[j2]−S[j1]>0$
$\large ∴2S[i]⩾ \frac{(dp[j_2]+(S[j_2]+L)^2)−(dp[j_1]+(S[j_1]+L)^2)}{S[j_2]−S[j_1]}$
设 $Y(j)=dp[j]+(S[j]+L)^2,X(j)=S[j]$
即$\large 2S[i]⩾ \frac{Y(j_2)−Y(j_1)}{X(j_2)−X(j_1)}$
显然等式右边是一个关于点 $P(j_2)$ 和 $P(j_1)$ 的斜率式,其中
$P(j)=(X(j),Y(j))=(S[j],dp[j]+(S[j]+L)^2)$
也就是说,如果存在两个决策点 $j_1,j_2$ 满足 $(0⩽j_1<j_2<i)$,使得不等式
$$\large \frac{Y(j_2)−Y(j_1)}{X(j_2)−X(j_1)}⩽2S[i]$$成立,或者说 使得 $P(j_2),P(j_1)$ 两点所形成直线的斜率小于等于 $2S[i]$,那么决策点 $j_2$ 优于 $j_1$。
> **划重点:斜优灵活多变,细节麻烦也多,所以尽量将问题模式化。**
比如这里的最终公式,尽量化为 $ \frac{Y(j)−Y(j′)}{X(j)−X(j′)}$的形式,而不是 $\frac{(Y(j))−Y(j′)}{X(j′)−X(j)}$ ,虽然直接做一般也不会出什么问题,但这样子可以方便理解,方便判断凸包方向等等。
假设有酱紫的三个点 $P(j_1),P(j_2),P(j_3)$,$k_1,k_2$ 为斜率,如下图所示情况(三点分别为 $A,B,C$):
<center><img src='https://images.cnblogs.com/cnblogs_com/Xing-Ling/1457207/o_464656465.PNG'></center>
显然有 $k_2<k_1$。设 $k_0=2S[i]$,由上述结论可知:
> ($a$). 若 $k_1⩽k_0$,则 $j_2$ 优于 $j_1$ 。反之,若 $k_1>k_0$,则 $j_1$ 优于 $j_2$ 。
> ($b$). 若 $k_2⩽k_0$,则 $j_3$ 优于 $j_2$ 。反之,若 $k_2>k_0$,则 $j_2$ 优于 $j_3$ 。
于是这里可以分三种情况来讨论:
> (1). $k_0<k_2<k_1$。由 $(a),(b)$ 可知:$j_1$ 优于 $j_2$ 优于 $j_3$。
> (2). $k_2⩽k_0<k_1$。由 $(a),(b)$ 可知:$j_1$ 和 $j_3$ 均优于 $j_2$。
> (3). $k_2<k_1⩽k_0$。由 $(a),(b)$ 可知:$j_3$ 优于 $j_2$ 优于 $j_1$。
可以发现,对于这三种情况,$j_2$ 始终不是最优解,于是我们可以将 $j_2$ 从**候选决策点**中踢出去(**删除**),只留下 $j_1$ 和 $j_3$,删后的情况如下图所示:
<center><img src='https://images.cnblogs.com/cnblogs_com/Xing-Ling/1457207/o_456.PNG'></center>
我们要对某一个问题的解决方案进行优化改进,无非就是关注两个要点:**正确性** 和 **高效性** (很多时候 **高效性** 都体现为 **单调性** )。
酱紫做的 **正确性** 是毋庸置疑的,因为在 $j_1$ 和 $j_3$ 其中必定有一个比 $j_2$ 更优,所以删除 $j_2$ 对答案没有任何影响。
那么高效性呢?自己在脑子里面 $yy$ 一下,在一个坐标系的第一象限中(本题中 $X(j)$ 和 $Y(j)$均大于等于 $0$,至于为什么这里要说等于,下面会提到),有若干个离散的点,任取三点,如果左边斜率大于右边斜率,则形成了上述情况,必定会 **删点** ,因而消除这种情况。所以将最后留下来的点首位相连,其形成的各个线段 **斜率** **从左到右** 必定是 **单调递增** 的(有可能非严格递增,这个问题之后再讨论)。
如果学习过计算几何相关知识,会意识到这个过程其实与求凸包算法是类似的。(顺手丢一个广告:[【学习笔记】计算几何全家桶](https://www.cnblogs.com/Xing-Ling/p/12102489.html))
实际上在图中选取最靠左下面、下面、右下面的点首位相连,就是最后留下来的点了,它们形成了一个 **下凸包**,即 **凸包**(又名 **凸壳**)的下半部分(不严谨的讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的 **凸多边形**,它能包含点集中所有的点——摘自 [百度百科](https://baike.baidu.com/item/%E5%87%B8%E5%8C%85/179150?fr=aladdin))。
维护出的图形如下图所示:
<center><img src='https://images.cnblogs.com/cnblogs_com/Xing-Ling/1457207/o_789.PNG'></center>
可以尝试在凸包围起来的区域内任意取一点,其必定能在包围圈上找到两个点使得该点可被删除。如上 $L$ 点,它与 $D,E$ 两点形成了一个 **可删点图形** 。
> 注意:图中 $C,D,E$ 故意画成了**三点一线**,而实际上点 $D$ 是可以删去的,且严格凸包不允许存在这种情况。关于去重的细节问题后面会提到。
**同理**,如果把不等式 $\large \frac{Y(j_2)−Y(j_1)}{X(j_2)−X(j_1)}⩽k_0[i]$ 改为 $\large \frac{Y(j_2)−Y(j_1)}{X(j_2)−X(j_1)}⩾k_0[i]$ ,那么维护出来的就是一个 **上凸包**。
##### (2).【寻找最优决策点】
在一次决策点的寻找中,易知 **下凸包** 点集里总会存在一点,使得它与左邻点形成的斜率小于等于 $k_0$ ,与右邻点形成的斜率大于 $k_0$ 。
例如上图中的 $E$ 点,设 $k_4⩽k_0<k_5$ 由于凸包上面的斜率呈 **单增态**,那么有:
$$\large k_1<k_2<k_3<k_4⩽k_0<k_5<k_6<k_7$$
所以决策点 $E$ 优于其他所有点,即 $E$ 就是 $dp[i]$ 的 **最优决策点**。
如果 **暴力查找** 的话,就是从第一个点开始向后扫描,找到 **第一个斜率大于 $k_0$ 的线段**,其 **左端点** 即为 **最优决策点**。由于凸包上的 **斜率依次递增**,可以 **二分** 快速得到这个点。
#### 2.【线性规划】
先回顾一下模板题的 $dp$ 方程:
$$\large dp[i]=S[i]^2−2S[i]L+dp[j]+(S[j]+L)^2−2S[i] \times S[j]$$
对其进行移项变化,变成形如 $y=kx+b$ 的点斜式。
> **划重点:移项要遵循的原则是:把含有 $function(i)∗function(j)$ 的表达式看作斜率 $k_0$ 乘以未知数 $x$,含有 $dp[i]$ 的项必须要在 $b$ 的表达式中,含有 $function(j)$ 的项必须在 $y$ 的表达式中。如果未知数 $x$ 的表达式单调递减,最好让等式两边同乘个 $−1$,使其变为单增。**
至于为什么说要让 $x$ 的表达式单增,$emm$...其实是为了让一些较简单的问题模式化,不易出错,如果你非要单减,可以尝试倒序枚举,至于是否正确,具体实现需要注意的玄学问题等等,因为觉得太麻烦没有细想,我也不清楚会遇到什么问题。
例如此题,原 $dp$ 方程可化为:
$$\large (2S[i])S[j]+(dp[i]−S[i]^2+2S[i]L)=(dp[j]+(S[j]+L)^2)$$
其中 $\large k_i=2S[i], x_i=S[j], b_i=dp[i]−S[i]^2+2S[i]L, y_i=dp[j]+(S[j]+L)^2$
其实也可以化为:
$$\large (2S[i])(S[j]+L)+(dp[i]−S[i]^2)=(dp[j]+(S[j]+L)^2)$$
其中 $\large k_i=2S[i], x_i=S[j]+L, b_i=dp[i]−S[i]^2, y_i=dp[j]+(S[j]+L)^2$
还可以化为 ...
...
只要满足上述移项原则,对答案是没有任何影响的。
这里以第一种形式为例,先画出草图:
<center><img src='https://images.cnblogs.com/cnblogs_com/Xing-Ling/1457207/o_14564864.PNG'></center>
##### (1).【高中数学知识】
我们的目的是求出一个最优决策点 $j$ 使得 $dp[i]$ 最小,又因为 $b[i]=dp[i]−S[i]^2+2S[i]L$ ,所以就是要找到某个点使这条直线经过它时算出来的 $b$ 最小,即是高中数学课本上的线性规划问题。
#### (2).【寻找最优决策点】
<center><img src='https://images.cnblogs.com/cnblogs_com/Xing-Ling/1457207/o_4684.PNG'></center>
如图所示,点 $E$ 即为 **最优决策点**。显然,这个使得 $b$ 最小的最优决策点位于下凸包点集中,且与上述代数法求得的点一致。
#### 3.【两种思考方式的结合】
强烈推荐用 **线性规划** 思想主导思考过程,因为图形的变幻较直观,更重要的是:在某某变量不满足单调性时,通过图形可以迅速做出判断并改变策略(在后面【关于单调性的研究】中会详细解释)。
而 **代数法** 通常在不便于识别方程特征时起一个转换思维方向的作用,因为有些题可能会直接出现 $\frac{Y(j)−Y(j′)}{X(j)−X(j′)}$ 的形式,需要通过一系列代数推导后再绘草图模拟决策。
### 二.【维护凸包】
实际上只要让维护的凸包方向相同,两种思考方式的代码是一模一样的。
用单调队列维护凸包点集,操作分三步走:
* (1). 进行 **择优筛选** 时,在凸包上找到 **最优决策点** $j$ 。
* (2). 用 **最优决策点** $j$ 更新 $dp[i]$ 。
* (3). 将 $i$ 作为一个决策点加入图形并更新凸包(如果点 $i$ 也是 $dp[i]$ 的决策点之一,则需要将 $(3)$ 换到最前面)。
在本题中步骤 $(3)$ 的具体操作为:判断当队尾的点与点 $i$ 形成可删点图形时,出队直至无法再删点,然后将 $i$ 加入队列。
在判断可删图形时有两种方法(以 **下凸包** 为例),一种是 `slope(Q[t-1],Q[t])<=slope(Q[t],i)`,另一种是 `slope(Q[t-1],Q[t])<=slope(Q[t-1],i)`,都表示出现了可以删去点 `Q[t]` 的情况(只要对边界、去重的处理足够严谨,两种写法是没有区别的)。其中 `Q` 是 **维护凸包点集** 的 **队列**。
该做法时间复杂度为 $O(nlogn)$,瓶颈在于二分寻找**最优决策点**。
### 三.【再优化】
运用 **决策单调性** 进行优化。**决策单调性** 相关基础知识见 [【学习笔记】动态规划—各种 $DP$ 优化](https://www.cnblogs.com/Xing-Ling/p/11317315.html),这里只放一下定义:
设 $j_0[i]$ 表示 $dp[i]$ 转移的 **最优决策点**,那么决策单调性可描述为 $∀i⩽i′,j_0[i]⩽j_0[i′]$。也就是说随着 $i$ 的增大,所找到的 **最优决策点是递增态**(非严格递增)。
#### (1).【决策单调性证明】
还是以 [玩具装箱](https://www.luogu.org/problemnew/show/P3195) 为例,来简单证一波 **决策单调性**,方法采用 **四边形不等式**。
**四边形不等式** 不知道是个啥,先去学习一下,然后继续。
2022.09.30
TODO
## (2).【单调队列】
## (3).【再证决策单调性】
# 五.【各种玄学问题】

View File

@@ -0,0 +1,25 @@
## 【四边形不等式】
### 前言
**四边形不等式** 是一种 **动态规划优化** 方法,通过对 **决策单调性** 的证明及应用,使得总体复杂度 **降低一个数量级** 。目前我见过的四边形不等式的题目不多,且大多数比较裸。四边形不等式的常见模型及其基础应用并不难,难点在于与四边形不等式相关的证明,尤其是题目中出现以前没有见过的转移方程的时候。由于本人数学很渣,所以问了很多大神,尝试了各种方法绕过证明。这里把我的经验分享给大家,尤其是像我一样的数学不好的同学。所以,本文并没有证明相关的东西,如果大家想看证明,可以阅读赵爽的文章《**动态规划加速原理之四边形不等式**》,百度文库上应该有免费下载。
### 一种基本形式
四边形不等式的基本形式非常简单,用于常见的区间$dp$的优化。
转移方程形式为
$$\large f[i][j] = min\{f[i][k] + f[k+1][j] + w(i,j)\}~~i <= k < j$$
这个方程大家再熟悉不过了,**长区间** 可以从 **短区间** 转移过来,$w(i,j)$表示将闭区间$[i,j]$合并产生的费用,状态有$O(n^2)$个,每个状态的决策有$O(n)$个,总复杂度为$O(n^3)$。
现在用 **四边形不等式** 对其优化,首先需要知道什么是 **四边形不等式** 。
若函数$w(i,j)$满足$w(a,c) + w(b,d) <= w(a,d) + w(b,c)$,其中$a <= b < c <= d$,则称$w$ **满足四边形不等式**。
可以看做一个以$(a,c)$为 **左上角**,$(b,d)$为 **右下角** 的矩阵中,**左上角** 的值 加上 **右下角**的值小于 **左下角** 的值加上 **右上角** 的值。注意我们要求$b < c$,因为在实际的区间问题中,既然$w(b,c)$表示合并区间$[b,c]$的费用,那么$b$一定是小于等于$c$的。在这个限制下,如果把我们所有的状态写成一个矩阵的话,有用的状态一定是行号小于等于列号的,即所有有用的状态$f[i][j]$中,$i <= j$。
挖坑待填 2022-09-30
[【教程】四边形不等式学习笔记](https://www.cnblogs.com/mlystdcall/p/6525962.html)