动态规划优化之斜率优化(基础)

原文链接http://www.cnblogs.com/zhouzhendong/p/8697303.html

前置技能

  • 知道什么是动态规划,并对一般的动态规划较为了解
  • 比较熟悉单调队列,并做过单调队列的题
  • 对斜率以及凸包有一定的了解
  • 有一定的推式子的能力

 

斜率优化可能是什么?

  顾名思义,就是通过一系列的推导把式子转化成斜率的形式,然后利用一些性质进行优化。

 

问题模型

  有一个长度为$n$的序列$a$,第$i$项元素为$a_i$。保证$a_i$为正整数。

  现在请你把这个序列分成若干段。设某一段是从$j$开始$i$结束的,设这个区间的所有的数字的总和为$x$,那么它的花费就是$V=ax^2+bx+c$(这里的a(a>0),b,c会输入,都是常数,别和序列$a$搞混)。

  一种划分方式的总花费就是他每一段的花费的和。

  问所有划分方式中总花费最小是多少。

  $n\leq 5\times 10^6$。

 

解决方法

  首先我们设$dp_i$表示序列前$i$个元素组成的前缀序列的最小总花费。

  设

  $$sum_i=\sum_{j=1}^{i}a_j$$

  我们可以列出DP方程:

  $$dp_i=max\{dp_j+a(sum_i-sum_j)^2+b(sum_i-sum_j)+c\}  (0\leq j<i)$$

  我们假设$j>k$且从$j$转移比从$k$不劣,则:

  $$dp_j+a(sum_i-sum_j)^2+b(sum_i-sum_j)+c\leq dp_k+a(sum_i-sum_k)^2+b(sum_i-sum_k)+c$$

  $$dp_j+a(sum_i-sum_j)^2+b(sum_i-sum_j)\leq dp_k+a(sum_i-sum_k)^2+b(sum_i-sum_k)$$

 

$$dp_j+a\cdot sum_i^2-2a\cdot sum_isum_j+a\cdot sum_j^2+b\cdot sum_i-b\cdot sum_j\leq dp_k+a\cdot sum_i^2-2a\cdot sum_isum_k+a\cdot sum_k^2+b\cdot sum_i-b\cdot sum_k$$

  $$dp_j-2a\cdot sum_isum_j+a\cdot sum_j^2-b\cdot sum_j\leq dp_k-2a\cdot sum_isum_k+a\cdot sum_k^2-b\cdot sum_k$$

  $$(dp_j+a\cdot sum_j^2-b\cdot sum_j)- (dp_k+a\cdot sum_k^2-b\cdot sum_k)\leq 2a\cdot sum_i(sum_j-sum_k)$$

  由于$sum$递增,而$j>k$,所以$sum_j-sum_k>0$,所以可以将上式继续转化:

  $$\frac{(dp_j+a\cdot sum_j^2-b\cdot sum_j)-(dp_k+a\cdot sum_k^2-b\cdot sum_k)}{sum_j-sum_k}\leq 2a\cdot sum_i$$

  我们设

  $$x_p=sum_p$$

  $$y_p=dp_p+a\cdot sum_p^2-b\cdot sum_p$$

  则原不等式可写为:

  $$\frac{y_j-y_k}{x_j-x_k}\leq 2a\cdot sum_i$$

  于是你会惊奇的发现,$\Large\frac{y_j-y_k}{x_j-x_k}$不就是斜率的式子吗?

  设

  $$g_{i,j}=\frac{y_i-y_j}{x_i-x_j}$$

  则上式可以表示为$g_{j,k}\leq sum_i$

  我们来发掘以下$g_{j,k}$的性质。

  1. 当$g_{j,k}\leq sum_i$时,由于随着$i$变大,$sum_i$也变大,所以显然从$k$转移是永远不会比$j$好的,所以我们可以把$k$扔掉。

  2. 当$g_{i,j}\leq g_{j,k}$时,从$i$或者$k$转移至少有一个不比$j$差,所以可以把$j$扔掉。为什么??

    若$g_{i,j}\leq sum_i$,显然$j$要被扔掉,根据第一个性质。

    若$g_{i,j}>sum_i$,则$g_{j,k}>sum_i$,那么显然$j$比$k$差,也得被扔掉。

  于是我们可以用一个单调队列来维护斜率的单调性。

  具体的:

  当情况1发生的时候让队首出队。

  在进队的时候,如果发生情况2,那么先让队尾出队,然后再进队。

  为了避免精度问题,我们可以把$x_i-x_j$乘上来。写成乘积的形式来比大小。

  显然每次要选队头的决策最赚。

  那么我们再思考一下,既然叫做斜率优化,那么显然有一些关于斜率的性质。

  我们如果把上述的决策放到单调队列里,然后再平面直角坐标系中描出这些点,并依次相连,会得到一个这样的图:

  

  然后你会发现这个右下角是个凸包的一部分。我们叫他下凸壳。

  然后你就和凸包联系起来了。

  由于博主见识短浅,所以不再进行凸包性质的拓展。

  读者可以自己科普。

  例子就这么快的讲完了,请读者好好回顾,务必理解。

  我直接开始放例题了。

例题

  以下例题链接是较为详细的题解(点击题号即可进入)。题解上部有题目链接。

BZOJ1911

题意

  把一个整数序列划分成任意连续的段,使得划分出来的每一段的价值和最大。对于某一段,价值的计算公式为 $V=ax^2+bx+c$,其中 $x$ 为当前段的数值和。

  $1\leq n\leq 1000000,-5\leq a\leq -1,|b|\leq 10000000,|c|\leq 10000000,1\leq xi\leq 100$

提示

  注意这题和例题非常相似,但是注意一个很大的不同!这里的$a$为负数。所以很多不等式符号都要取相反方向。

 

 

BZOJ1597

题意

  有N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地的价格是它的面积,但可以同时购买多快土地. 这些土地的价格是它们最大的长乘以它们最大的宽, 但是土地的长宽不能交换. 如果FJ买一块3x5的地和一块5x3的地,则他需要付5x5=25. FJ希望买下所有的土地,但是他发现分组来买这些土地可以节省经费. 他需要你帮助他找到最小的经费.

提示

  考虑到如果长方形A的长和款都比B小,那么A就可以附着在B里面买,而且不加花费,所以这些可以删掉,是没用的。

  本题由于是我很久以前做的,题解没有用Latex,所以特别丑,请别介意。

  请注意两块相同土地的情况,别全都删光。

  然后把土地按照长升序排列,得到的土地的宽必然是降序的,所以就可以很快写出DP方程并斜率优化了。

 

BZOJ1010

题意

  划分序列,每一段的花费为$(i-j+(\sum_{k=i}^j C_k)-L)^2$,问最小花费。序列长度$\leq 5\times 10^4$。

提示

  DP方程应该很好写吧。

  手工展开式子得到关于$i$的二次项,关于$j$的二次项,以及$k\cdot ij$这种形式。

  根据斜率优化的套路,把只含$i$的左右消掉,把含$i,j$或者$i,k$的移向同一侧,然后除过来。

 

BZOJ3156

题意

  长为$n$的序列$A$划分,设某一段为$[i,j]$,则其花费为$A_j+\sum_{k=i}^{j}(j-k)$。最小化总花费。$n\leq 10^6$。

提示

  同样也是化开,再按照斜率优化的套路来。

  为了避免精度问题,我们可以通过把$x,y$同时乘上一个常数来除去分母对精度的影响。

 

BZOJ3437

题意

  每一段的花费为$a_i+\sum_{k=j+1}^{i}(i-k)b_k$.最小化总花费。$n\leq 10^6$。

提示

  考虑预处理带权前缀和$vsum_i=\sum_{j=1}^{i}(j\cdot b_j)$。

  

BZOJ1096

题意

  每一段的花费为$a_i+\sum_{k=j+1}^{i}(X_i-X_k)b_k$.最小化总花费。$n\leq 10^6$。

提示

  上一题的一个小小的升级版。

  考虑把预处理的带权前缀和改为$vsum_i=\sum_{j=1}^{i}(X_jb_j)$。

 

BZOJ3675

题意

  对于一个非负整数序列,小H需要重复k次以下的步骤:

  1.选择一个长度超过1的序列

  2.从任意位置将序列分割成两个非空的新序列。

  每次,小H将会得到分数。分数为两个新序列中元素和的乘积。请选择一种最佳的分割方式,使得k轮之后,使总得分最大。输出总得分。

  $n\leq 10^5,k\leq min(n-1,200)$

提示

  这题比较不错。

  首先证明一个性质:对于一个最终的划分方案,以各种不同顺序划分,所得到的得分总是相同。

  然后$dp_{r,i}$表示划分到前$i$个,划分了$r$轮的最大总得分。然后斜率优化。

  注意空间限制较紧,要滚动。

 

BZOJ4409

题意

  有一个N个点的环,相邻两个点距离是1。点顺时针标号为1..N。最初每一个点是空的。要求最终点i存在ri头牛。你有∑ri头牛。你可以选择最多k个点,然后把你的牛任意分配在这k个点里。之后,每一头牛可以选择不动,也可以顺时针走d格并呆在那里。这样,它要耗费d的能量。通过合理选择点、合理分配牛、合理安排牛的走动,使得消耗的总能量最小。

  $n\leq 1000,k\leq 7,r_i\leq 10^6$

提示

  先证明一个小小的性质。

  然后断环为链,并参照BZOJ3675以及BZOJ1096的做法。

  注意初始化$dp_{0,i}$为$\infty$。

posted @ 2018-04-02 20:49  zzd233  阅读(680)  评论(0编辑  收藏  举报