• [HNOI2008]玩具装箱TOY


    题目描述

    P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为x,其制作费用为(X-L)^2.其中L是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过L。但他希望费用最小.

    输入输出格式

    输入格式:

    第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7

    输出格式:

    输出最小费用

    输入输出样例

    输入样例#1:
    5 4
    3
    4
    2
    1
    4
    输出样例#1:
    1

    题解:
    上题一样的套路哈.直接写出原始dp方程,f[i]=f[j]+(sum[i]-sum[j]+i-j-L-1)^2
    但是天真的小朋友,千万把后面一块全拆.分i,j两部分即可
    变为f[i]=f[j]+((sum[i]+i-L-1)+(-j-sum[j]))^2 然后开平方
    最后变为斜率优化的标准形式:
    (f[j]-f[k]+(j+sum[j])^2-(k+sum[k])^2)/(2*((-k-sum[k])-(-j-sum[j])))<=(sum[i]+i-L-1)
    那么(sum[i]+i-L+1)就是当前直线斜率,
    (f[j]-f[k]+(j+sum[j])^2-(k+sum[k])^2)就是y,(2*((-k-sum[k])-(-j-sum[j])))就是x.
    直接维护凸壳即可 代码好写
     1 #include <algorithm>
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 using namespace std;
     8 typedef long long ll;
     9 const int N=50005;
    10 ll sum[N];
    11 int gi(){
    12     int str=0;char ch=getchar();
    13     while(ch>'9' || ch<'0')ch=getchar();
    14     while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
    15     return str;
    16 }
    17 int n,m,q[N];ll f[N];
    18 ll fy(int i,int j){
    19     return f[i]+(i+sum[i])*(i+sum[i])-f[j]-(j+sum[j])*(j+sum[j]);
    20 }
    21 ll fx(int i,int j){
    22     return ((-(-i-sum[i])+(-j-sum[j]))<<1);
    23 }
    24 void work(){
    25     n=gi();m=gi();
    26     for(int i=1,x;i<=n;i++)x=gi(),sum[i]=sum[i-1]+x;
    27     int l=1,r=1,j,k;q[1]=0;
    28     for(int i=1;i<=n;i++){
    29         while(l<=r-1){
    30             j=q[l];k=q[l+1];
    31             if(fy(j,k)>=fx(j,k)*(sum[i]+i-m-1))l++;
    32             else break;
    33         }
    34         f[i]=f[q[l]]+(sum[i]-sum[q[l]]+i-q[l]-1-m)*(sum[i]-sum[q[l]]+i-q[l]-1-m);
    35         while(l<=r-1){
    36             j=q[r];k=q[r-1];
    37             if(fy(i,j)*fx(j,k)<=fx(i,j)*fy(j,k))r--;
    38             else break;
    39         }
    40         q[++r]=i;
    41     }
    42     printf("%lld
    ",f[n]);
    43 }
    44 int main()
    45 {
    46     work();
    47     return 0;
    48 }
     
    
    
    
    


  • 相关阅读:
    [考试]20150811
    [考试]20150810
    [随笔]暑假过了,暑假来了
    [考试]20150808
    动态规划大合集II
    [知识点][旧版]C++中的运算符
    NOIP动态规划大合集
    [考试]20150729
    [考试]20150728
    /=============分隔线=============/
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7242636.html
Copyright © 2020-2023  润新知