zoukankan      html  css  js  c++  java
  • dp

    (原来的题解没得了,只好重写一份)

    斜率优化一般是,(dp) 是枚举一个 (i),然后前面找一个 (j),式子中有些和 (j) 有关,有些和 (i) 有关,有些和俩都有关。

    过程中,我们维护一个单调队列,它们可能作为最优的转移位置。其中队首是最优的,其它的是 可能 成为最优的(现在不是,可能以后)

    核心步骤:把每个决策转化成平面直角坐标系上的点,然后从几何的角度考虑哪些点可能是最优的,哪些不可能。

    我们发现这个性质好像很妙。所以说,不是所有题都可以斜率优化的。

    这些说的肯定非常迷惑,看个实际的

    示例

    最经典的入门题 HNOI2008玩具装箱

    转移方程为 (f_i=min(f_j+(s_i-s_j+i-j-L-1)^2)),非常 simple

    我们令和 (i) 有关的为 (a_i=s_i+i),和 (j) 有关的为 (b_j=s_j+j+L+1)

    (f_i=min(f_j+(a_i-b_j)^2))

    拆开 (f_i=min(f_j+a_i^2-2a_ib_j+b_j^2))

    假设 (j) 是最优的那个转移,那

    (f_i=f_j+a_i^2-2a_ib_j+b_j^2)

    这个式子里面,注意到 (2a_ib_j) 这一项是同时与俩有关的。

    主体思想

    我们把和 (i) 有关的那个 (2a_i) 看成斜率,和 (j) 有关的 (b_j) 看成 (x)。那 (y) 肯定也要和 (j) 有关,移到右边。我们的主体思想是把 (f_i) 变成一个截距。所以把 (f_i) 和一些只和 (i) 有关的东西放到左边。

    (这一步就体现出“斜率”了)

    变成 (2a_ib_j+f_i-a_i^2=b_j^2+f_j)。其中 (x=b_j)(y=b_j^2+f_j)

    (P_j) 作为第 (j) 个决策点,坐标为 ((b_j,b_j^2+f_j))

    那现在问题转化成了:找到一个 (j<i),使得过点 (P_j) 的斜率为 (2a_i)(定值)的直线的截距加上 (a_i^2)(定值)最小。

    手画几张图可以得出以下结论:

    • 如果队首的斜率 (<2a_i),那这一次转移队首就比队首的下一个要劣(画图发现);而且 (a_i) 是单增的,那以后肯定都劣,直接弹队首
    • 斜率应该是单调递增的 (这个要手画了)。所以如果新来的和原队尾组成的斜率,小于原队尾和原队尾上一个的斜率,那这个队尾就废了

    然后就维护一个单调队列就完事了。复杂度是 (O(n)) 的,(log) 都不带。

    代码

  • 相关阅读:
    1、编写一个简单的C++程序
    96. Unique Binary Search Trees
    python 操作redis
    json.loads的一个很有意思的现象
    No changes detected
    leetcode 127 wordladder
    django uwsgi websocket踩坑
    you need to build uWSGI with SSL support to use the websocket handshake api function !!!
    pyinstaller 出现str error
    数据库的读现象
  • 原文地址:https://www.cnblogs.com/LightningUZ/p/13818271.html
Copyright © 2011-2022 走看看