DP的各类优化(动态规划,决策单调性,斜率优化,带权二分,单调栈,单调队列)

前缀和优化

当DP过程当中须要反复从一个求和式转移的话,能够先把它预处理一下。运算通常都要知足可减性。php

比较naive就不展开了。html

题目

【Todo】洛谷P2513 [HAOI2009]逆序对数列算法

【Done】洛谷P2511 [HAOI2008]木棍分割数据结构

【Done】洛谷P4099 [HEOI2013]SAO函数

【Done】NOIAC37 染色优化

单调队列优化

前置技能:单调队列(经典的问题模型:洛谷P1886 滑动窗口ui

用于优化形如\(f_i=\min/\max_{j=l_i}^{i-1}\{g_j\}+w_i\),且知足\(l_i\le l_{i+1}\)的转移。spa

人话:对于序列中的每一个点,从其左侧一段决策区间内的最值进行转移,且决策区间随着序列下标的增大也不断右移(就像窗口向右滑动)。.net

\(j<k\),容易发现若是\(g_j\)劣于\(g_k\)的话,那么当决策区间移动到\(k\)之后,\(j\)永远不会成为最优决策点,不再会被转移了。指针

因而,咱们只要维护一个队列,知足下标递增,决策性递减。咱们须要当前的队首成为最优决策点,那么当队首第一次超出了区间范围(之后也就永远超出了)就把它出队。为了保证单调性,队尾新加入点以前,要先把队列中比它劣的点依次从队尾出队。

题目

Sol.洛谷P1776 宝物筛选_NOI导刊2010提升(02)(就是多重背包)

【Done】洛谷P2254 [NOI2005]瑰丽华尔兹

【Todo】洛谷P2569 [SCOI2010]股票交易

【Todo】洛谷P3572 [POI2014]PTA-Little Bird

【Todo】洛谷P3594 [POI2015]WIL-Wilcze doły

决策单调性

通常分两类。不管是哪一类都须要细心发现决策之间的递变规律。

一种是用于优化形如\(f_{i}=\min/\max w_{i,j}\)且对于每个\(i\)和它的最优决策点\(j\)都有单调性的方程。

这样的方程对题目的性质要求较高(由于\(j\)是独立的)。

只须要维护指针,按照单调性不断寻找最优答案便可。

update:上面提到的这一种好像不在狭义的决策单调性的定义内。。。应该能够叫双指针优化。

另外一种是形如\(f_i=\min/\max_{j=1}^{i-1} g_j+w_{i,j}\),且记\(f_i\)的最优决策点为\(p_i\)(也就是\(f_i\)\(g_{p_i}+w_{i,p_i}\)处转移最优)若知足\(p_i\le p_{i+1}\),则该方程知足决策单调性。

在诗人小G的题解中蒟蒻用数形结合的思想讨论了一种可能能够快速准确地判断一个转移方程是否知足决策单调性的方法。

由于\(j\)不独立了,因此咱们只能把有用的决策先存起来。

策略1——二分栈

咱们使用决策二分栈(一种单调栈)来维护全部有用的决策,其中栈顶是当前最优决策。

为何叫二分栈呢?

咱们能够把\(g_j+w_{i,j}\)视为关于\(j\)的函数。由于决策单调,因此对于栈中的任意相邻两个决策点,咱们均可以经过二分找到一个临界值\(k\),使得序列中在\(k\)以前的时候,其中一个做为决策转移到\(f_k\)更优,而\(k\)之后另外一个更优。能够借助函数图像来理解这个过程。

咱们须要栈顶为当前的最优解。而若是栈中有不止一个元素,则可能存在一个\(i\),使获得\(i\)以后栈里面的决策比栈顶优了。这个时候,如何快速判断并弹掉栈顶呢?

上面提到的这个可二分的性质就派上用场了。对于当前的\(i\),若是当前栈顶下面与栈顶相邻的决策在\(i\)以前就比栈顶更优了,就要把栈顶弹掉。

这是决策单调性的基本思想,具体的题目实现起来也不同。诸若有的题为了扩展功能,还须要把单调栈换成单调队列,等等。

策略2——分治

然而二分栈有一个局限性,那就是必须能快速计算\(w_{i,j}\)。若是不能\(O(1)\)算的话,在求临界值\(k\)的时候复杂度会严重退化。

既然转移过程是单调而且离线的,咱们考虑分治。假设当前咱们求解一段区间\(f_{l,r}\),而全部\(f_{l,r}\)的最优决策点在\([L,R]\)之间。对于\([l,r]\)的中点\(mid\),咱们能够暴力扫一遍\(L-mid\),找到它的最优决策点\(k\)。由于决策单调,因此\(f_{l,mid-1}\)的决策落在\([L,k]\)上,而\(f_{mid+1,r}\)的决策落在\([k,R]\)上,变成了两个规模减半的小问题。

套用分治的复杂度分析,总的时间也是\(n\log n\)的。


两种策略的代码难度都不大呢~

废话,DP固然是重在思惟啦!

题目

类型1

Sol.洛谷P1973 [NOI2011]Noi嘉年华

【Todo】洛谷P3724 [AH2017/HNOI2017]大佬

类型2

【Done】BZOJ4709 [Jsoi2011]柠檬

Sol.洛谷P3515 [POI2011]Lightning Conductor

Sol.洛谷P1912 [NOI2009]诗人小G

Sol.CF868F Yet Another Minimization Problem洛谷)(vjudge

斜率优化

与决策单调性有着说不清的联系。

仍然是转移方程形如\(f_i=\min_{j=1}^{i-1}g_j+w_{i,j}\)\(\max\)同理)

考虑两个决策\(j_1,j_2\),若是\(j_1\)\(j_2\)优,那么\(g_{j_1}+w_{i,j_1}\le g_{j_2}+w_{i,j_2}\)

这时候根据题目特色把\(w\)展开,若是式子能化成\(\frac{y_{j_1}-y_{j_2}}{x_{j_1}-x_{j_2}}\le k_i\)的形式,那么咱们把每一个决策当作点\((x_j,y_j)\)分布在坐标系上,而真正有用的决策点实际上造成了一个凸壳。(由相似线性规划的寻找最优解的过程能够发现)

上面这段很差理解?下面第一题的Sol对两种理解斜率优化的方法作了更详细的分析(最好看第二种,由于第一种有针对性,不通用)(有图片哟qwq)

因而咱们用数据结构维护凸壳上的全部点,具体实现依题而定。

不论是什么题,加入决策点的时候要保证斜率递增/递减。

若是\(x\)单调,能够用单调栈维护凸壳,转移时使用当前直线的斜率(线性规划),在栈内二分最优解。

若是斜率\(k\)单调,那么用单调队列维护凸壳,队首为当前最优决策。转移以前若是队首不优就出队。

引用MashiroSky学长的更完整的套路总结(他的总结戳这里

  斜率单调暴力移指针
  斜率不单调二分找答案
  x坐标单调开单调队列
  x坐标不单调开平衡树|cdq分治

题目

Sol.洛谷P2900 [USACO08MAR]土地征用Land Acquisition

【Todo】洛谷P3195 [HNOI2008]玩具装箱TOY

Sol.洛谷P3628 [APIO2010]特别行动队

【Todo】洛谷P4360 [CEOI2004]锯木厂选址

【Todo】洛谷P2305 [NOI2014]购票

【Todo】洛谷P1721 [NOI2016]国王饮水记

DP凸优化/WQS二分/带权二分

WQS的论文(在线)(下载

这种算法用来解决一类问题——有\(n\)个物品,规定以若干方式选择物品有若干代价,须要在强制选出\(C\)个物品的前提下最大/最小化代价。

通常来讲,适用此算法的题目还要有以下一些特色:(设关于\(x\)的函数\(g(x)\)为强制选\(x\)个物品的最值)

  1. 咱们没法直接求出\(g(C)\)的值(废话,否则干吗不直接求);
  2. 咱们能够直接求出\(g\)的最值,以及使\(g(x)\)取到最值的\(x\)
  3. \(g\)是一个凸函数。

蒟蒻再解释这是个什么东东也比不上Creeper_LKF大佬的blog来的清楚明白了。

但是,有没有大佬和蒟蒻同样以为用二分斜率切凸包的这种思路有点很差理解呢?

受超级大佬学哥的启发,蒟蒻想试着用原函数与导数的相互转化来理解咱们寻找恰好选取\(C\)个物品时的最优解。

这是\(g(x)\)(上方蓝色曲线)和\(g'(x)\)(下方红色曲线)

\(C=7\),如今咱们的任务就是求出\(g(7)\)

显然,由于\(g(x)\)是凸的,因此\(g'(x)\)是单调递减的。咱们能够求出如今\(g(x)\)的最值,有什么特色呢?看看\(g'(x)\)\(x\)轴相交的地方,不就是在这个点处\(g(x)\)取到最值么?

然而这个交点\(x=5\),不是咱们想要的。若是咱们能把函数膜改一下,使导函数的交点挪到\(x=7\),那该有多好!

\(f(x)=g(x)+kx\)\(k\)的现实意义是,咱们每多选一个物品,就要多付出\(k\)的代价。

\(k\)的函数意义又是什么呢?咱们显然能够发现\(f'(x)=g'(x)+k\),至关于导函数向上平移了\(k\)个单位!而导函数是递减的,若是咱们把它向上平移,那它与\(x\)轴的交点就会向右移了。等于说\(k\)越大交点的\(x\)也越大。这个样子是可二分的。

因而咱们对\(k\)进行二分,\(k\)的值域就是导函数的值域。咱们作一遍DP,在原有的转移基础上,每多选一个物品还要额外加上\(k\)的代价。最后,咱们能够求得\(f(x)\)的极值点,也就是\(f'(x)\)\(x\)轴的交点。若是这个交点\(x<C\)说明咱们仍需继续调大\(k\),不然就是调小咯。

如今咱们试着模拟一下。一开始\(k\)等于\(0\)的时候交点\(x=5<C\),咱们就把\(k\)调大一点点。

图中多了\(f(x)\)(上方绿色曲线)和\(f'(x)\)(下方橙色曲线)

如今的交点\(x=9\),又比\(7\)大了,咱们调小\(k\)

又通过若干调整,咱们终于使得交点落在了\(C\)这个位置。

那么咱们要求出\(g(C)\)了。咱们如今求出的是\(f(C)\),只须要\(g(C)=f(C)-kC\)便可,等于说减掉函数图像中\(f(x)\)\(g(x)\)\(C\)处的高度差。

看上去须要小数二分?不是这样的。在实际的DP问题中\(x\)确定都是整数点,那么\(g(x)\)确定是一段一段的折线,\(g'(x)\)就是一段一段的水平线,等于说取遍\(g'(x)\)的整数点的值就能取遍\(g'(x)\)的整个值域了。因而在整数内二分便可。

注意上面的\(g(x)\)是上凸的,若是\(g(x)\)下凸那么\(g'(x)\)递增,二分的方向还要变一下。

题目

Sol.洛谷P2619 [国家集训队2]Tree I(不是DP,但有助于理解带权二分)

Sol.洛谷P4072 [SDOI2016]征途

【Done】洛谷P4383 [八省联考2018]林克卡特树lct

【Todo】BZOJ5311贞鱼

【Todo】洛谷CF739E Gosha is hunting

相关文章
相关标签/搜索