• 【bzoj1010】玩具装箱toy——斜率优化dp


    题目链接

    第一道自己推的斜率优化dp><

    首先要明确一点:装进同一个容器的toys一定要是连着的几个(否则的话可以直接贪心)-->之前理解错题意WA了一次......

    用sum[i]表示前缀和,f[i]表示前i个装进容器的最小费用,

    容易知道

      f[i]=max(f[i],f[j]+(sum[i]-sum[j]+i-(j+1)-l)2)(j<i)

    令k<j<i,若要使f[j]>f[k],则需要满足:

      f[j]+(sum[i]-sum[j]+i-(j+1)-l)2<f[k]+(sum[i]-sum[k]+i-(k+1)-l)2

    t[i]=sum[i]+i,则移项,可得:

      f[j]-f[k]+(t[j]-t[k])*(t[j]+t[k])<2(t[i]-l-1)(t[j]-t[k])

    即:

      (f[j]-f[k]+t[j]2-t[k]2)/(t[j]-t[k])<2*(t[i]-l-1)

    g[i]=f[i]+t[i]2,则有

      (g[j]-g[k])/(t[j]-t[k])<2*(t[i]-l-1)。

    用s(i,j)表示i到j连线的斜率,

    对于一个单调队列,每次对于队首,若s(q[h],q[h+1])<2*(ti-l-1),则此时的q[h]一定不会是现在和以后的最优解,h++;

    对于队尾,若s(q[t-2],q[t-1])>s(q[t-1],i),如果s(q[t-2],q[t-1])<2*(t[i]-l-1),则s(q[t-1],i)<2*(t[i]-l-1),由i>q[t-1]可知此时i比q[t-1]要优;如果s(q[t-2],q[t-1])>2*(t[i]-l-1),则q[t-2]要比q[t-1]优。所以无论如何q[t-1]都不会是最优解,此时t--。

    接着就是斜率优化dp的套路了:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 typedef long long LL;
     5 const int maxn=5e4+5;
     6 using namespace std;
     7 LL a[maxn],q[maxn],sum[maxn],g[maxn],t[maxn],f[maxn];
     8 inline LL read()
     9 {
    10     LL anss=0,f=1;char c=getchar();
    11     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    12     while(c>='0'&&c<='9'){anss=anss*10+c-48;c=getchar();}
    13     return anss*f;
    14 }
    15 inline double cal(LL a,LL b)
    16 {
    17     return 1.0*(g[a]-g[b])/(t[a]-t[b]);
    18 }
    19 int main()
    20 {
    21     int n,l;
    22     sum[0]=0;
    23     scanf("%d %d",&n,&l);
    24     for(int i=1;i<=n;i++){
    25         a[i]=read();
    26         sum[i]=sum[i-1]+a[i];
    27         t[i]=sum[i]+i;
    28     }
    29     int h=0,ta=1;q[0]=0;
    30     for(int i=1;i<=n;i++)
    31     {
    32         while(h<ta-1&&cal(q[h],q[h+1])<2*(t[i]-l-1))h++;
    33         f[i]=f[q[h]]+(t[i]-t[q[h]]-l-1)*(t[i]-t[q[h]]-l-1);
    34         g[i]=f[i]+t[i]*t[i];
    35         while(h<ta-1&&cal(q[ta-1],q[ta-2])>cal(q[ta-1],i))ta--;
    36         q[ta++]=i;
    37     }
    38     printf("%lld",f[n]);
    39     return 0;
    40 }
    bzoj1010
  • 相关阅读:
    榫卯游戏介绍
    如果你有一个域名,你也可以免费有一个diy@yourdomain.com的企业邮局
    封装一个axios请求后台的通用方法
    javascript判断两个对象属性以及值是否相等
    遍历出文档内所有元素的tagName
    windows下nginx的安装及使用方法入门
    css样式重置样式
    canvas绘图
    表单脚本
    javascript事件
  • 原文地址:https://www.cnblogs.com/JKAI/p/7460495.html
Copyright © 2020-2023  润新知