【学习笔记】斜率优化 DP
2026/7/23 11:46:23 网站建设 项目流程

算法介绍
在平时的 DP 过程中,我们可能会遇到这样的 DP 式子:



min







(



+


×


+


+


+

)
dp
i

j=i−x
min
i−y

(dp
j

+a
i

×b
j

+c
i

+d
j

+M)
单调队列优化 DP 拼劲全力无法战胜,只能请它大哥出场了。

推导一
动态规划当然要考虑最优决策点的位置呀!所以我们假设现在有

1
,

2
(

1
<

2
)
j
1

,j
2

(j
1

<j
2

) 两个决策点,如果

2
j
2

更优秀,应该满足的条件是酱紫的:




2
+


×


2
+


+


2
+





1
+


×


1
+


+


1
+




2
+


×


2
+


2




1
+


×


1
+


1



×
(


1



2
)

(



1
+


1
)

(



2
+


2
)
dp
j
2


+a
i

×b
j
2


+c
i

+d
j
2


+M
dp
j
2


+a
i

×b
j
2


+d
j
2

−a
i

×(b
j
1


−b
j
2


)

≤dp
j
1


+a
i

×b
j
1


+c
i

+d
j
1


+M
≤dp
j
1


+a
i

×b
j
1


+d
j
1

≤(dp
j
1


+d
j
1


)−(dp
j
2


+d
j
2


)

如果


1



2

0
b
j
1


−b
j
2


=0,那么我们就会得到这个不等式:




(



1
+


1
)

(



2
+


2
)


1



2
a
i


b
j
1


−b
j
2

(dp
j
1


+d
j
1


)−(dp
j
2


+d
j
2


)

如果


1



2

0
b
j
1


−b
j
2


=0,你可以认为上面那个值是

∞。

这里我们令

(

)



,

(

)




+


X(i)=b
i

,Y(i)=dp
i

+d
i

,那么不等式变为:





(

1
)


(

2
)

(

1
)


(

2
)
a
i


X(j
1

)−X(j
2

)
Y(j
1

)−Y(j
2

)


(

(

)
,

(

)
)
(X(j),Y(j)) 作为

j 的对应点放入平面。如果

1
j
1



2
j
2

构成的直线斜率小于等于


a
i

(这里

1
,

2
j
1

,j
2

作为决策点出现),那么

2
j
2

优于

1
j
1

;否则

1
j
1

优于

2
j
2

假设


[



,



]
j∈[i−x,i−y],那么下图的点就是对应到平面上的散点:

我们把目光放到

,

,

A,B,C 三个点上,这里假设

,

A,B 构成的直线斜率是

1
k
1



,

B,C 构成的直线斜率是

2
k
2

,此处我们钦定

1


2
k
1

k
2

如果

2
<

1



k
2

<k
1

≤a
i

,那么

C 是最优点
如果

2



<

1
k
2

≤a
i

<k
1

,那么

C 是最优点
如果


<

2
<

1
a
i

<k
2

<k
1

,那么

A 是最优点
也就是说,

B 永远不会存为最优点,就要淘汰掉(太馋人,哦不太残忍了)。

同样的道理,这里看似有这么多点,但实则只有下凸包上的点会用到:

又因为下凸包的斜率是单调递增的,如果

j 前面的斜率都是小于等于


a
i

,后面的斜率都是


a
i

,那么

j 就是当前的最优决策点。

那不对呀!上凸包怎么能被忽略呢?!

所以如果上面不等式是




(

1
)


(

2
)

(

1
)


(

2
)
a
i


X(j
1

)−X(j
2

)
Y(j
1

)−Y(j
2

)

的话,那么决策点就在上凸包上啦!

推导二
TA 回来了:



min







(



+


×


+


+


+

)
dp
i

j=i−x
min
i−y

(dp
j

+a
i

×b
j

+c
i

+d
j

+M)
先假装看不见
min

min:






+


×


+


+


+

dp
i

=dp
j

+a
i

×b
j

+c
i

+d
j

+M
进一步:




+




×


+








dp
j

+d
j

=−a
i

×b
j

+dp
i

−c
i

−m




+


,




,



,









y=dp
j

+d
j

,k=−a
i

,x=b
j

,b=dp
i

−c
i

−m,那么上式就变成了



+

y=kx+b,此时最小化



dp
i

就相当于最小化

b。

怎样移向呢?看法则:


,

x,y 与

i 无关

,

k,b 与

j 无关

b 中要有我们要求的



dp
i

我们把每一个

,

x,y 当成一个点对应到平面上,这就是我们的决策点。接着我们用



[

]
k=−a[i] 的直线去对准每一个点(如图),看看哪条直线的截距(也就是

b)最小就好了。

你看,最优决策点的位置不变,说明最优决策点还是在下凸包的斜率单峰处。

当然,最大化

b 就是上凸包。

总结
其实它们本质是相同的,可以相辅相成地来理解。

接下来,明白了最优决策点在什么位置,那该怎么快速地找最优决策点呢?

如果状态转移决策具有决策单调性(放在刚才的例子里就是


,



∀i>j,a
i

a
j

,即二次项系数


a
i

单调递增,此时随着和斜率比较的


a
i

的不断增加,由于下凸包上的点单调递增,


a
i

卡到下凸包上的点一定越来越靠后),则可以用单调队列维护凸包上的点(单调队列返厂啦!)。
如果不具有决策单调性,则根据凸包的单调性二分即可。
例题讲解
P3195 [HNOI2008] 玩具装箱
题目分析
状态设计:定义



dp
i

表示对于前

i 个玩具,若

i 作为所属分组的最后一个玩具,求总的最小花费。
转移方程:



=
min


=
1


1
{


    (


    (

    +
    1
    )
    +
    (





    )


    )
    2
    }
    dp
    i

    j=1
    min
    i−1

    {dp
    j

    +(i−(j+1)+(
    k=j

    i

    C
    k

    )−L)
    2
    }



    1



    ,


    +
    1
    S
    i

    =∑
    j=1
    i

    C
    j

    ,M=L+1,则转移方程变为:



    min

    1


    1
    {



    +
    (







    )
    2
    }
    dp
    i

    j=1
    min
    i−1

    {dp
    j

    +(S
    i

    −S
    j

    −M)
    2
    }
    拆开:



    min

    1


    1
    {



    +


    2
    +


    2
    +

    2

    2





    2



    +
    2



    }
    dp
    i

    j=1
    min
    i−1

    {dp
    j

    +S
    i
    2

    +S
    j
    2

    +M
    2
    −2S
    i

    S
    j

    −2S
    i

    M+2S
    j

    M}
    发现了
    2




    2S
    i

    S
    j

    ,因此斜率优化必定了。

    状态初始化:


    0

    0
    dp
    0

    =0。
    答案就是



    dp
    n

    如果当前状态为



    dp
    i

    ,若存在决策点

    1
    ,

    2
    (

    1
    <

    2
    )
    j
    1

    ,j
    2

    (j
    1

    <j
    2

    ),且

    2
    j
    2

    优于

    1
    j
    1

    ,则:




    2
    +


    2
    +


    2
    2
    +

    2

    2




    2

    2



    +
    2


    2





    1
    +


    2
    +


    1
    2
    +

    2

    2




    1

    2



    +
    2


    1




    2
    +


    2
    2

    2




    2
    +
    2


    2





    1
    +


    1
    2

    2




    1
    +
    2


    1

    2


    (


    1



    2
    )

    (



    1
    +


    1
    2
    +
    2


    1

    )

    (



    2
    +


    2
    2
    +
    2


    2

    )




    1
    ,


    1


    2



    1



    2

    0
    2



    (



    1
    +


    1
    2
    +
    2


    1

    )

    (



    2
    +


    2
    2
    +
    2


    2

    )


    1



    2
    dp
    j
    2


    +S
    i
    2

    +S
    j
    2

    2

    +M
    2
    −2S
    i

    S
    j
    2


    −2S
    i

    M+2S
    j
    2


    M
    dp
    j
    2


    +S
    j
    2

    2

    −2S
    i

    S
    j
    2


    +2S
    j
    2


    M
    2S
    i

    (S
    j
    1


    −S
    j
    2


    )
    2S
    i

    ≤dp
    j
    1


    +S
    i
    2

    +S
    j
    1

    2

    +M
    2
    −2S
    i

    S
    j
    1


    −2S
    i

    M+2S
    j
    1


    M
    ≤dp
    j
    1


    +S
    j
    1

    2

    −2S
    i

    S
    j
    1


    +2S
    j
    1


    M
    ≥(dp
    j
    1


    +S
    j
    1

    2

    +2S
    j
    1


    M)−(dp
    j
    2


    +S
    j
    2

    2

    +2S
    j
    2


    M)
    ∵C
    i

    ≥1, j
    1


    =j
    2

    ∴S
    j
    1


    −S
    j
    2


    =0

    S
    j
    1


    −S
    j
    2

    (dp
    j
    1


    +S
    j
    1

    2

    +2S
    j
    1


    M)−(dp
    j
    2


    +S
    j
    2

    2

    +2S
    j
    2


    M)



    (

    )



    ,


    (

    )



    [

    ]
    +


    2
    +
    2



    X(j)=S
    j

    , Y(j)=dp[j]+S
    j
    2

    +2S
    j

    M,得:

    2




    (

    1
    )


    (

    2
    )

    (

    1
    )


    (

    2
    )
    2S
    i


    X(j
    1

    )−X(j
    2

    )
    Y(j
    1

    )−Y(j
    2

    )

    满足此条件时有

    2
    j
    2

    优于

    1
    j
    1

    ,则根据原理处的推导,只需要维护


    [
    1
    ,


    1
    ]
    j∈[1,i−1] 对应的点集
    (

    (

    )
    ,

    (

    )
    )
    (X(j),Y(j)) 的下凸包即可。

    又由于


    S
    i

    单调递增,所以状态转移具有决策单调性,可以用单调队列维护,即不是

    i 的最优决策点的点不会再是

    +
    1
    i+1 的最优决策点。

    注意:

    单调队列中维护凸包上的点对应的

    j。
    维护的点不应存在三点共线,而应当只维护两端点。
    单调队列中应保证至少有两个点再求斜率,deque 难以实现且常数大,建议使用手写队列。
    维护凸包比较斜率时建议不要使用除法,容易被卡精度,交叉相乘是更好的选择。同时,

    0



    0
    a


    c
    b

    交叉相乘后恒成立,这难道不正是我们一直在找的

    0


    0
    a

    =∞ 的可行实现方案吗?
    代码实现
    cpp
    #include <bits/stdc++.h>
    #define int long long
    using namespace std;

    const int N = 5e4 + 10;
    int n, L, c[N];
    int dp[N], s[N], a[N], b[N];
    int q[N], h = 1, t = 1;
    int X(int p) { return b[p]; }
    int Y(int p) { return dp[p] + b[p] * b[p]; }
    double slope(int a, int b) {
    if (X(a) == X(b)) {
    if (Y(a) == Y(b)) return 0; // 斜率无法比较
    if (Y(a) > Y(b)) return -1e18; // 斜率为负无穷
    else return 1e18; // 斜率为正无穷
    }
    return (Y(a) - Y(b)) * 1.00 / (X(a) - X(b));
    }

    signed main() {
    scanf(“%lld%lld”, &n, &L);
    for (int i = 1; i <= n; i++) scanf(“%lld”, &c[i]), s[i] = s[i - 1] + c[i];
    for (int i = 0; i <= n; i++) a[i] = s[i] + i, b[i] = s[i] + i + L + 1;
    q[1] = 0;
    for (int i = 1; i <= n; i++) {
    // 由于凸包的斜率一定单调递增,于是把队头斜率小于 2 * a[i] 的点删除
    while (h < t && slope(q[h], q[h + 1]) <= 2 * a[i]) h++;
    int j = q[h];
    dp[i] = dp[j] + (a[i] - b[j]) * (a[i] - b[j]); // 状态转移方程
    // 把队尾的斜率小于当前点的坐标删除,放入当前点
    while (h < t && slope(q[t - 1], q[t]) >= slope(q[t], i)) t–;
    q[++t] = i;
    }
    printf(“%lld\n”, dp[n]);
    return 0;
    }
    P2365 [IOI 2002] 任务安排
    题目分析
    状态设计:用



    ,

    dp
    i,j

    表示前

    i 个任务分成

    j 组,

    i 为第

    j 组最后一个任务,完成所有任务所需时间的最小值。
    转移方程:



    ,

    min



    1


    <




    ,


    1
    +


    +
    1





    ×


    +

    min



    1


    <




    ,


    1
    +




    ×


    +
    1



    +

    dp
    i,j

    =
    j−1≤k<i
    min

    dp
    k,j−1

    +
    p=k+1

    i

    tim
    j

    ×f
    k

    +s

    j−1≤k<i
    min

    dp
    k,j−1

    +tim
    j

    ×
    p=k+1

    i

    f
    k

    +s

    优化一下,假设


    1





    ,


    1



    T
    i

    =∑
    j=1
    i

    tim
    j

    ,F
    i

    =∑
    j=1
    i

    f
    j


    则上式变为:




    ,

    min



    1


    <




    ,


    1
    +




    ×
    (





    )
    dp
    i,j

    j−1≤k<i
    min

    dp
    k,j−1

    +tim
    j

    ×(F
    i

    −F
    k

    )

    需要专业的网站建设服务?

    联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

    立即咨询