当前位置: 首页 > news >正文

DP 优化专题

常见思路:

  • 减少状态量:滚动数组等。

  • 加速决策过程:二分、数据结构等。

  • 缩小决策范围:单调队列/栈、斜率优化、四边形不等式优化等。

  • 技巧性优化:前缀和等。

本文主要针对第三点展开讲解。

斜率优化

斜率优化的题目通常具有以下特征:

  • 转移方程中含有乘积式,通常用平方得到。

  • 有一些具有单调性的东西,如前缀和等。

尤其是第一点,是斜率优化题目极为明显的特征。

接下来,我们从一个经典题目入手,详细讲解它的原理逻辑。

P3195

很容易设计朴素 dp。

\(dp_i\) 表示压缩前 \(i\) 个玩具所需要的最小代价。

答案:\(dp_n\),初始:\(dp_0=0\)

转移:考虑对于每个 \(i\) 枚举 \(last\),尝试将 \(last+1 \sim i\) 都放入一个容器,则 \(dp_i=dp_{last}+(i-last-1+\sum^i_{j=last} C_j-L)^2\),其中 \(\sum\) 可以前缀和维护。

这样做的时间复杂度 \(\mathcal{O}(n^2)\),无法接受。

注意到,\(dp_{last}\) 加上的东西是个乘积式,并且前缀和具有单调性,于是考虑斜率优化。

钦定 \(j,k\) 满足 \(k<j\),且以 \(j\) 作为决策点比 \(k\) 更优。则有(以下令前缀和数组为 \(s_i\)):

\[dp_j+(i-j-1+s_i-s_j-L)^2 \le dp_k+(i-k-1+s_i-s_k-L)^2 \]

不妨设 \(h_{i,j}=i-j-1+s_i-s_j\),则有:

\[dp_j+(h_{i,j}-L)^2 \le dp_k+(h_{i,k}-L)^2\\ dp_j+h_{i,j}^2+L^2-2h_{i,j}L \le dp_k+h_{i,k}^2+L^2-2h_{i,k}L\\ dp_j+h_{i,j}^2-2h_{i,j}L \le dp_k+h_{i,k}^2-2h_{i,k}L \]

不妨再设 \(g_i=i+s_i-1,w_j=s_j+j\),则有:

\[dp_j+(g_i-w_j)^2-2(g_i-w_j)L \le dp_k+(g_i-w_k)^2-2(g_i-w_k)L\\ dp_j+g_i^2+w_j^2-2g_iw_j-2g_iL+2w_jL \le dp_k+g_i^2+w_k^2-2g_iw_k-2g_iL+2w_kL\\ dp_j+w_j^2-2g_iw_j+2w_jL \le dp_k+w_k^2-2g_iw_k+2w_kL\\ \]

把含有 \(g_i\) 的项放到一边,其余的放到另一边,得到:

\[(dp_j+w_j^2+2w_jL)-(dp_k+w_k^2+2w_kL) \le 2g_i(w_j-w_k)\\ \dfrac{(dp_j+w_j^2+2w_jL)-(dp_k+w_k^2+2w_kL)}{w_j-w_k} \le 2g_i \]

实际上,\(g_i=w_i-1\),于是整理得:

\[\dfrac{(dp_j+w_j^2)-(dp_k+w_k^2)+2L(w_j-w_k)}{w_j-w_k} \le 2(w_i-1)\\ \dfrac{(dp_j+w_j^2)-(dp_k+w_k^2)}{w_j-w_k}+2L \le 2(w_i-1)\\ \dfrac{(dp_j+w_j^2)-(dp_k+w_k^2)}{w_j-w_k} \le 2(w_i-L-1) \]

换元,令 \(y_i=dp_i+w_i^2,x_i=w_i\),得:

\[\dfrac{y_j-y_k}{x_j-x_k} \le 2(w_i-L-1) \]

左边这个式子长得很像直线的斜率,故称此方法为斜率优化(Convex Hull Trick)

这个式子表明,在当前 \(i\) 的前提下,当一对 \(j,k\) 满足 \(k<j\) 且满足上式时,\(j\) 一定更优。

那么,\(i+1\) 时是否同样成立?因为前缀和单调不减,所以 \(2(w_i-L-1)\) 同样单调不减,因此 \(i+1\) 时显然成立。

于是,我们可以维护一个单调队列,每次剔除不优的队头,然后从队头转移。在插入 \(i\) 进入队列时,我希望斜率越来越大(因为不等式右边在变大),所以当队尾和次队尾的斜率比队尾和 \(i\) 的斜率小,我就弹出队尾(总不能弹出 \(i\) 吧,这样的话就不会有新的决策点进入了)。

由于每个决策点至多进队/出队一次,因此时间复杂度 \(\mathcal{O}(n)\)

实现
#include<bits/stdc++.h>
#define int long long
using namespace std;const int N=5e5+5;
int n,m;
int dp[N],sum[N],q[N],h[N];int up(int j,int k){return (dp[j]+h[j]*h[j])-(dp[k]+h[k]*h[k]);
}
int down(int j,int k){return h[j]-h[k];
}
void sol(){cin>>n>>m;for(int i=1;i<=n;i++)cin>>sum[i],sum[i]+=sum[i-1];int l=1,r=0;q[++r]=0;for(int i=1;i<=n;i++){h[i]=sum[i]+i;for(;l<r&&up(q[l+1],q[l])<=2*(h[i]-m-1)*down(q[l+1],q[l]);l++);dp[i]=dp[q[l]]+(sum[i]-sum[q[l]]+i-q[l]-1-m)*(sum[i]-sum[q[l]]+i-q[l]-1-m);for(;l<r&&up(i,q[r])*down(q[r],q[r-1])<=up(q[r],q[r-1])*down(i,q[r]);r--);q[++r]=i;}cout<<dp[n]<<'\n';
} signed main(){ios::sync_with_stdio(0);cin.tie(0);sol();return 0;
}

事实上,因为队列中的斜率递增,所以我们维护的决策点集合相当于一个下凸壳。如图:

image

(红线标出的是下凸壳,\(\texttt{x-axis}\)\(w_i\)\(\texttt{y-axis}\)\(dp_i+w_i^2\)

这也是为什么斜率优化的英文名是「Convex Hull Trick」,即所谓「凸包技巧」。

http://www.aitangshan.cn/news/83.html

相关文章:

  • Git 常用命令总结
  • 解决 计算机有两个python环境导致 Pygal 模块导入错误
  • 详解:GPT-5 API如何在国内无限制使用?OpenAI最新发布的这款模型到底有何过人之处?
  • Linux Makefile
  • 【高等数学】第八章 向量代数与空间解析几何——第三节 平面及其方程 - 指南
  • 字符串的最大公因子
  • YACS2025年6月乙组
  • chrony时间同步服务详解
  • SAP工厂erp管理系统软件-适合生产型企业的erp系统推荐
  • 我去,Gitee官方推荐的开源项目,这程序我是不能干了,这功能真是逆天了
  • ArcGISProject工程文档的使用学习笔记
  • 8.4 ~ 8.10
  • MeshCN 太阳能 Mesh 网络:SX1262 芯片赋能,无网无电也能畅联
  • 中电金信 :从通用狂飙到穿透场景,行业智能化落地没有捷径
  • wls ssh 连接异常 Missing privilege separation directory: /run/sshd
  • Prometheus源码专题【左扬精讲】—— 监控系统 Prometheus 3.4.0 源码解析:scrape manager 与 scrapeLoop
  • 洛谷P13030 [GCJ 2021 #1B] Subtransmutation
  • idempiere安装
  • 如何安装 Git (windows/mac/linux)
  • 拆解Agent如何实现“听懂→规划→搞定”全流程
  • ActiveMQ 设置用户名密码
  • MySQL 8.0.42 手动部署全过程(CentOS 7 虚拟机 Linux)
  • PDF处理控件Aspose.PDF教程:在C#、Java、Python中快速缩小PDF
  • 自动化测试框架选型指南:5大主流工具实战对比
  • Re:从零开始的动态凸壳
  • 资产管理系统 - microsoft
  • G1 垃圾回收器调优
  • 面相对象编程:类和对象
  • 学习笔记:Query Transformation- Distinct Aggregate Transformation
  • 安卓