斜率优化

斜率优化


前置技能点:

闲话:

前面写这么多都是为了写这个做准备的…本来还应该写一下凸包,但凸包算法比较多,迟点吧…

问题:

给定非负整数序列 a a a长度为 n n n,状态转移方程为 D P [ i ] = min ⁡ k = 1 i ( D P [ k ] + ( s u m [ i ] − s u m [ k ] ) 2 + C ) DP[i]=\min_{k=1}^{i}(DP[k]+(sum[i]-sum[k])^2+C) DP[i]=mink=1i(DP[k]+(sum[i]sum[k])2+C),求DP[n]

思路:

最朴素的做法,有状态方程就对着做, f o r ( i ) for(i) for(i) f o r ( k ) for(k) for(k),复杂度 O ( n 2 ) O(n^2) O(n2)

概念引入:

D P k [ i ] = D P [ k ] + ( s u m [ i ] − s u m [ k ] ) 2 + C DP_k[i]=DP[k]+(sum[i]-sum[k])^2+C DPk[i]=DP[k]+(sum[i]sum[k])2+C j < p j<p j<p D P p [ i ] DP_p[i] DPp[i] D P j [ i ] DP_j[i] DPj[i]


D P j [ i ] ≥ D P p [ i ] DP_j[i]≥DP_p[i] DPj[i]DPp[i]

D P [ j ] + ( s u m [ i ] − s u m [ j ] ) 2 + C ≥ D P [ p ] + ( s u m [ i ] − s u m [ p ] ) 2 + C DP[j]+{(sum[i]-sum[j])}^2+C≥DP[p]+{(sum[i]-sum[p])}^2+C DP[j]+(sum[i]sum[j])2+CDP[p]+(sum[i]sum[p])2+C 拆开

D P [ j ] − 2 ∗ s u m [ i ] ∗ s u m [ j ] + s u m [ j ] 2 ≥ D P [ p ] − 2 ∗ s u m [ i ] ∗ s u m [ p ] + s u m [ p ] 2 DP[j]-2*sum[i]*sum[j]+{sum[j]}^2≥DP[p]-2*sum[i]*sum[p]+{sum[p]}^2 DP[j]2sum[i]sum[j]+sum[j]2DP[p]2sum[i]sum[p]+sum[p]2 拆开平方项并消去常数 s u m [ i ] 2 sum[i]^2 sum[i]2 C C C

( D P [ j ] + s u m [ j ] 2 ) − ( D P [ p ] + s u m [ p ] 2 ) ≥ 2 ∗ s u m [ i ] ∗ ( s u m [ j ] − s u m [ p ] ) (DP[j]+{sum[j]}^2)-(DP[p]+{sum[p]}^2)≥2*sum[i]*(sum[j]-sum[p]) (DP[j]+sum[j]2)(DP[p]+sum[p]2)2sum[i](sum[j]sum[p]) 移项


f ( x ) = D P [ x ] + s u m [ x ] 2 f(x)=DP[x]+{sum[x]}^2 f(x)=DP[x]+sum[x]2 g ( x ) = 2 ∗ s u m [ x ] g(x)=2*sum[x] g(x)=2sum[x] h ( x ) = s u m [ x ] h(x)=sum[x] h(x)=sum[x]

则原式等价于 f ( j ) − f ( p ) ≥ h ( i ) ∗ ( g ( j ) − g ( p ) ) f(j)-f(p)≥h(i)*(g(j)-g(p)) f(j)f(p)h(i)(g(j)g(p))

由于g(x)单调不降

两边同除以 ( g ( j ) − g ( p ) ) (g(j)-g(p)) (g(j)g(p))(事实上可能为0,不能除,这里是为了看上去直观一点)得到:

f ( j ) − f ( p ) g ( j ) − g ( p ) ≤ h ( i ) \frac{f(j)-f(p)}{g(j)-g(p)}≤h(i) g(j)g(p)f(j)f(p)h(i)

而由于 h ( i ) h(i) h(i)单调不降, g ( j ) − g ( p ) ≤ 0 g(j)-g(p)≤0 g(j)g(p)0故当 i i i增大时,不等式恒成立

也即是一旦对于 D P [ i ] DP[i] DP[i],不等式成立,则对于任意 i ′ > i i'>i i>i不等式恒成立,即决策点p永远优于决策点j

定义使得 D P k [ x ] DP_k[x] DPk[x]取得最小值的点 k k k p [ x ] p[x] p[x](perfect)。

这意味着,对于要得到的 D P [ i ] DP[i] DP[i],我们只需要将 p [ i − 1 ] p[i-1] p[i1] i − 1 i-1 i1的所有元素遍历一遍即可得到 p [ i ] p[i] p[i]

目前还属于常数剪枝,不影响复杂度…


现在,以 g ( x ) g(x) g(x) x x x轴, f ( x ) f(x) f(x) y y y轴建立直角坐标系,由于 g ( x ) g(x) g(x)递增,故输入的每个元素的顺序与其在x轴上的顺序相同。

将所有下标为 p [ i − 1 ] p[i-1] p[i1] i − 1 i-1 i1的点画到图上,方便起见,就画三个点 l , m , r l,m,r l,m,r

回顾之前的式子

f ( j ) − f ( p ) g ( j ) − g ( p ) ≤ h ( i ) \frac{f(j)-f(p)}{g(j)-g(p)}≤h(i) g(j)g(p)f(j)f(p)h(i)

不难发现左边部分在这个直角坐标系上就是 j , p j,p j,p两点间的斜率。

k 1 = k ( l , m ) k_1=k(l,m) k1=k(l,m) k 2 = k ( m , r ) k_2=k(m,r) k2=k(m,r) k 3 = k ( l , r ) k_3=k(l,r) k3=k(l,r)

一共有两种情况:

  • k 1 ≥ k 2 k_1≥k_2 k1k2

  • k 1 < k 2 k_1<k2 k1<k2
    这里写图片描述
    我们分开来讨论

  • 情况 1
    k 1 ≥ k 3 ≥ k 2 k_1≥k_3≥k_2 k1k3k2
    对于一个给定的 h ( i ) h(i) h(i),若
    h ( i ) ≥ k 1 h(i)≥k_1 h(i)k1,则 m m m点比 l l l点更优,但同时 h ( i ) ≥ k 2 h(i)≥k_2 h(i)k2,故 r r r点在三点中最优。
    k 1 > h ( i ) ≥ k 3 k_1>h(i)≥k_3 k1>h(i)k3,则 r r r点比 l l l点更优,同时 h ( i ) ≥ k 2 h(i)≥k_2 h(i)k2,故 r r r点在三点中最优。
    k 3 > h ( i ) ≥ k 2 k_3>h(i)≥k_2 k3>h(i)k2,则 r r r点比 m m m点更优,但 h ( i ) < k 3 h(i)<k_3 h(i)<k3,故 l l l点在三点中最优。
    k 2 > h ( i ) k_2>h(i) k2>h(i),则 l l l点在三点中最优。
    也即是当出现这种情况时, m m m点根本没有判定的必要,只需要判定 k ( l , r ) k(l,r) k(l,r) h ( i ) h(i) h(i)的关系即可。

  • 情况 2
    k 2 > k 3 > k 1 k_2>k_3>k_1 k2k3k1
    对于一个给定的 h ( i ) h(i) h(i),若
    h ( i ) ≥ k 2 h(i)≥k_2 h(i)k2,则 r r r点比 m m m点更优,同时 h ( i ) ≥ k 1 h(i)≥k_1 h(i)k1,故 r r r点在三点中最优。
    k 2 > h ( i ) ≥ k 3 k_2>h(i)≥k_3 k2>h(i)k3,则 r r r点比 l l l点更优,但 h ( i ) < k 2 h(i)<k_2 h(i)<k2,故 m m m点在三点中最优。
    k 3 > h ( i ) ≥ k 1 k_3>h(i)≥k_1 k3>h(i)k1,则 m m m点比 l l l点更优,同时 h ( i ) < k 2 h(i)<k_2 h(i)<k2,故 m m m点在三点中最优。
    k 1 > h ( i ) k_1>h(i) k1>h(i),则 l l l点在三点中最优。
    也即是当出现这种情况时,我们不需要考虑 k ( l , r ) k(l,r) k(l,r),只需要考虑相邻两点之间的斜率即可。

得到了上面的结论后,我们可以用水平法求下凸包进行优化,但是点 p [ i − 1 ] p[i-1] p[i1]可能会因为 i − 1 i-1 i1的进入而在做下凸包时被删除。
所以我们需要知道新加的元素导致凸包尾被删除到了哪个点,在进行 p [ i ] p[i] p[i]的求值时,以此判断是从 p [ i − 1 ] p[i-1] p[i1]还是直接从单调栈中最后两个元素开始对斜率进行判定。

此外还有另一个办法,我们注意到即使存在点 j < p [ i − 1 ] < i − 1 j<p[i-1]<i-1 j<p[i1]<i1使得出现之前讨论过的情况1,但实际上从点 p [ i − 1 ] p[i-1] p[i1]到点 i − 1 i-1 i1的斜率一样足以让我们判定点 i − 1 i-1 i1优于点 p [ i − 1 ] p[i-1] p[i1] h ( i ) ≥ h ( i − 1 ) ≥ k 1 h(i)≥h(i-1)≥k_1 h(i)h(i1)k1

所以我们可以通过直接移动栈底,即单调队列的弹出队头操作来维护得到 p [ i ] p[i] p[i] i − 1 i-1 i1之间的下凸包,而非从 1 1 1 i − 1 i-1 i1之间的下凸包。

两个方法的代码几乎没有不同,第二个可能快点吧,但第一种方法能顺便得到下凸包。

复杂度:

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

例题

  • hdu 3507
    就是上面的问题,给定非负整数序列 a a a长度为 n n n,状态转移方程为 D P [ i ] = min ⁡ k = 1 i ( D P [ k ] + ( s u m [ i ] − s u m [ k ] ) 2 + C ) DP[i]=\min_{k=1}^{i}(DP[k]+(sum[i]-sum[k])^2+C) DP[i]=mink=1i(DP[k]+(sum[i]sum[k])2+C),求DP[n]
    解题报告
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值