zoukankan      html  css  js  c++  java
  • 斜率优化 学习笔记

    前言:寒假Yousiki讲过斜率优化,但完全没有听懂。现在文化课解析几何也学了不少,终于能做一些题了。

    -----------------

    有时候我们列出DP方程会得到形如这样的式子:

    $f[i]=max/min{f[j]+(a[i]-b[j])^2}+w[i](1leq j<i)$(其实平不平方都随便啦)这个式子复杂度是$O(n^2)$的。

    我们变换一下形式:

    $2*a[i]*b[j]+f[i]-a[i]^2-w[i]=f[j]+b[j]^2$

    仔细一看,上面的等式可以化成$y=kx+b$的形式,即含$j$的项视为$x$和$y$,含$i$的项视为常数项。

    根据这个式子,我们可以将转移优化成$O(n)$的。

    根据$y=kx+b$的形式,我们可以视为平面上有许多点,坐标为$(b[j],f[j]+b[j]^2)$。这些点连起来可以形成一个凸包。我们用单调队列来维护这个凸包。

    假设$k=2*a[i]>0$,即维护下凸包,斜率是单调递增的。下面的讲述可以用线性规划来理解(人教版高中数学必修二)。

    1.如果经过某两点直线的斜率小于现在直线的斜率,那么$head++$。因为我们现在的直线肯定是想经过凸包的边界的,而现在的答案肯定不是最优。

    2.现在的队头就是最优解。把$q[head]$带到原方程中。

    3.如果经过$q[tail]$和$q[tail-1]$的直线的斜率大于经过$q[tail-1]$和$i$的斜率,那么$tail--$。因为凸包肯定是要囊括所有点的,不能让有的点在凸包外面。

    于是转移被优化成$O(n)$的了。

    怎么样?是不是很简单?滑稽

    其实学长教我们的时候推荐我们用叉积来判断关系,因为会有些极端数据卡掉斜率(比如斜率不存在)。但大部分题都不卡斜率这种做法。

    -------------------------------

    例题 【HNOI2008】玩具装箱

    题目链接

    斜率优化入门题。

    设$f[i]$表示考虑前$i$个玩具所花费的最小费用,很容易得出方程$f[i]=min{f[j]+((i-j-1-L)+sumlimits_{k=i-j+1}^i c[k])^2}$

    前缀和优化,变换一下形式:$f[i]=min(f[j]+(sum[i]-sum[j]+i-j-1-L)^2)$

    设$a[i]=sum[i]+i$,$b[i]=sum[i]+i+L+1$

    则$f[i]=min(f[j]+(a[i]-b[j])^2)$

    化成$y=kx+b$的形式:$2*a[i]*b[j]+f[i]-a[i]^2=f[j]+b[j]^2$

    然后斜率优化一下就可以了。

    代码:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    int dp[50005],n,L,x;
    double sum[50005];
    int Q[50005],head,tail;
    double a(int x) {return sum[x]+x;}
    double b(int x){return a(x)+L+1;}
    double X(int x){return b(x);}
    double Y(int x){return dp[x]+b(x)*b(x);}
    double slope(int i,int j){return (Y(i)-Y(j))/(X(i)-X(j));}
    signed main()
    {
        scanf("%d%d",&n,&L);
        for(int i=1;i<=n;i++){
            scanf("%lf",&sum[i]);
            sum[i]+=sum[i-1];
        }
        head=tail=1;
        for(int i=1;i<=n;i++){
            while(head<tail&&slope(Q[head],Q[head+1])<2*a(i)) ++head;
            dp[i]=dp[Q[head]]+(a(i)-b(Q[head]))*(a(i)-b(Q[head]));
            while(head<tail&&slope(i,Q[tail-1])<slope(Q[tail-1],Q[tail])) --tail;
            Q[++tail]=i;
        }
        printf("%lld",dp[n]);
        return 0;
    }
  • 相关阅读:
    body标签中l的相关标签
    PostgreSQL&PostGIS完全安装
    PostgreSQL常用函数
    Linux 路由 学习笔记 之一 相关的数据结构
    OSPF学习中的问题
    对TCP重传的进一步认识
    TCP 接收窗口自动调节
    [转]struct 用法深入探索
    Memcached缓存瓶颈分析
    C++的try_catch异常
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13304021.html
Copyright © 2011-2022 走看看