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;
    }
  • 相关阅读:
    服务端增加WCF服务全局异常处理机制
    ASP.NET MVC异常处理方案
    [你必须知道的异步编程]C# 5.0 新特性——Async和Await使异步编程更简单
    Asp.Net Mvc的几个小问题
    C# 多线程之Thread类
    C#泛型
    c#public、private、protected、internal、protected internal
    ASP.NET并发处理
    GDB调试器的使用
    【多媒体封装格式详解】---MKV
  • 原文地址:https://www.cnblogs.com/mrsheep/p/8387263.html
Copyright © 2011-2022 走看看