zoukankan      html  css  js  c++  java
  • 斜率优化第一题! HDU3507 | 单调队列优化DP

    放一手原题


    题解:

    第一次写(抄)斜率优化,心里还是有点小激动的。讲一下怎么实现的!

    首先我们可以考虑一个朴素的dp:DP[i]表示前i个数字的最少花费,显然我们有一个转移方程

    DP[i]=min{DP[j]+M+(sum[i]-sum[j])^2}

    但是N^2肯定会超时,我们考虑优化他

    假设有k<j<i,如果令j对i的贡献比k好

    显然我们有这样的式子

    DP[j]+M+(sum[i]-sum[j])^2 < DP[k]+M+(sum[i]-sum[j])^2

    把平方打开之后移项

    可以得到

     ((DP[j]+sum[j]^2)- (DP[k]+sum[k]^2) )  / 2*(sum[j]-sum[k]) < sum[i]

    可以把这个式子看成(yj - yk)/(xj - xk) 这样就得到了一个类似斜率的式子!

    有了这些结论有什么用呢?

    令G[i,j]表示刚刚的斜率式,依然有k<j<i

    当j的决策比k优秀的时候,则满足G[i,j]>G[j,k]

    我们可以用单调队列维护解集,利用斜率判断元素的入队和出队,这样可以使时间复杂度降低到O(n)了

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define N 500005
    using namespace std;
    int dp[N],q[N],sum[N],l,r,n,m;
    int GetDp(int i,int j)
    {
        return dp[j]+m+(sum[i]-sum[j])*(sum[i]-sum[j]);
    }
    int GetUp(int j,int k)
    {
        return dp[j]+sum[j]*sum[j]-(dp[k]+sum[k]*sum[k]);
    }
    int GetDown(int j,int k)
    {
        return 2*(sum[j]-sum[k]);
    }
    int main()
    {
        while (scanf("%d%d",&n,&m)!=EOF)
        {
            for (int i=1,x;i<=n;i++)
                scanf("%d",&x),sum[i]=sum[i-1]+x;
            l=r=0;
            q[r++]=0;
            for (int i=1;i<=n;i++)
            {
                while (l+1<r && GetUp(q[l+1],q[l])<=sum[i]*GetDown(q[l+1],q[l]))
                    l++;
                dp[i]=GetDp(i,q[l]);
                while (l+1<r && GetUp(i,q[r-1])*GetDown(q[r-1],q[r-2])<=GetUp(q[r-1],q[r-2])*GetDown(i,q[r-1]))
                    r--;
                q[r++]=i;
            }
            printf("%d
    ",dp[n]);
        }
        return 0;
    }
  • 相关阅读:
    IOS-button属性edge
    IOS-简单WebView的使用
    IOS-绘制饼图等多种图形
    IOS-Prefix.pch 文件不起作用
    IOS-根据ip获取当前城市的编号
    在iis中调试asp.net程序
    asp.net跨域上传文件
    用jQuery的ajax请求一般处理程序返回json数据
    SQLServer分页
    Visual Studio发布项目到远程服务器的步骤
  • 原文地址:https://www.cnblogs.com/mrsheep/p/8387263.html
Copyright © 2011-2022 走看看