zoukankan      html  css  js  c++  java
  • [HNOI2008]玩具装箱TOY

    显然dp方程可以得出为dp[i]=min{dp[j]+(sum[i]+isum[j]jL1)2}

    但是这种dp方式是O(n2)的,我们可以使用斜率优化的方法将其优化成O(n)

    我们考虑将原DP方程变形

    1.  dp[i]=dp[j]+(sum[i]+isum[j]jL1)2      将L++

    2.  dp[i]=dp[j]+(sum[i]+isum[j]jL)2          令sum[i]+=i

    3.  dp[i]=dp[j]+(sum[i]sum[j]L)2

    将原式子展开

    dp[j]+sum[i]2+(sum[j]+L)2=2*sum[i]*(sum[j]+L)+dp[i]

          y                 =     k      *        x       +  b

    y=dp[j]+sum[i]2+(sum[j]+L)2     k=2*sum[i]   x=sum[j]+L   b=dp[i]

    所以我们将每一个点(x,y)画在图像上,并维护一个凹包

    那么我们在求f[i]的值的时候,用一条斜率为2*sum[i]的线切上它能切到的最低点

    此时其与y轴的交点的截距为f[i]的最小值

    又因为sum[i]单调递增,所以k值只会越来越大

    所以选中点前的点全部废弃

     因为每个点只会被删一次,所以算法为O(n)

    实现采用单调队列:

    #include <algorithm>
    #include <iostream>
    #include <cmath>
    #include <cstring>
    #include <map>
    #include <string>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <cstdio>
    #include <cstdlib>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        register ll p(1),a(0);register char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
        if(ch=='-') p=-1,ch=getchar();
        while(ch>='0'&&ch<='9') a=a*10+ch-48,ch=getchar();
        return a*p;
    }
    const int N=50010;
    ll n,L,f[N],s[N],Q[N],head=1,tail=1;
    //f[i]+2*s[i]*(s[j]+L)=f[j]+s[i]^2+(s[j]+L)^2
    double getx(int x) {return s[x];}
    double gety(int x) {return f[x]+(s[x]+L)*(s[x]+L);}
    double che(int x,int y){return (gety(y)-gety(x))/(getx(y)-getx(x));}
    int main()
    {
    //    freopen("input","r",stdin);
    //    freopen("output","w",stdout);
        n=read(),L=read()+1;
        for(int i=1;i<=n;i++) s[i]=s[i-1]+read();
        for(int i=1;i<=n;i++) s[i]+=i;
        for(int i=1,j;i<=n;i++)
        {
            while(head<tail&&che(Q[head],Q[head+1])<2*s[i]) ++head;
            j=Q[head];f[i]=f[j]+(s[i]-s[j]-L)*(s[i]-s[j]-L);
            while(head<tail&&che(Q[tail-1],Q[tail])>che(Q[tail],i)) --tail;
            Q[++tail]=i;
        }
        printf("%lld",f[n]);
        return 0;
    }
    /*
    
    */
  • 相关阅读:
    关于三次握手与四次挥手你要知道这些
    seafile看不见repo报500错误的解决方法
    VMWare Workstation 配置docker多macvlan网络方法
    利用Python3的dpkt库进行ARP扫描
    关于LAMP配置Let’s Encrypt SSL证书
    OpenSSL生成CA证书及终端用户证书
    CentOS7.2安装Vim8和YouCompleteMe
    CentOS 7.2安装Jenkins自动构建Git项目
    CentOS 7.2 安装Gerrit 2.14.6
    CentOS7.2编译GCC7.3
  • 原文地址:https://www.cnblogs.com/cold-cold/p/10103100.html
Copyright © 2011-2022 走看看