zoukankan      html  css  js  c++  java
  • BZOJ 1010 [HNOI2008]玩具装箱toy

    1010: [HNOI2008]玩具装箱toy

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 7184  Solved: 2724
    [Submit][Status][Discuss]

    Description

    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。但他希望费用最小.

    Input

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

    Output

    输出最小费用

    Sample Input

    5 4
    3
    4
    2
    1
    4

    Sample Output

    1

    HINT

     

    Source

    题解:laishao_yuan:Dp先入脑

    有一个Dp[i]:=min(Dp[j]+(sum[i]-sum[j]+i-j-1-L)^2)的基本思路
    预处理可以得到F[i]:=sum[i]+i;令C=L+1
    可以简化方程:Dp[i]:=min(Dp[j]+(F[i]-F[j]-c)^2))
    明显这个为O(N^2)的算法,,要再简化;
    一维的Dp可以想到斜率优化
     
    所谓斜率优化,个人的感悟就是:
    当 I:1-->n J:1-->n的N^2循环时 可以简化J的循环 把1~N依次入队出队,当i要选择j时,先根据最优策略缩短队列,再在选取队首元素直接作为J,算出Dp[i];
    这样做的话每个数进出一次队列 复杂度就变为O(n);
     
    但是这样做必须证明单调性,也就是出队的元素在以后的Dp中不会再被利用
     
    下面说说怎么缩短队列
    Dp[i]:=min(Dp[j]+(F[i]-F[j]-c)^2))中j的选择是决定Dp[i]的大小的 而 f[i]、c这样的常量是不变的(对于同一个i来说)
    所以我们把不含j的变量分离出来,方便运算
    Dp[i]:=min(Dp[j]+F[j]^2-2F[i]F[j]+2F[j]*c)+F[i]^2+c^2-2*F[i]*c;
    假设选j好过选k, 本题为
    Dp[j]+F[j]^2-2F[i]F[j]+2F[j]*c<Dp[k]+F[k]^2-2F[i]F[k]+2F[k]*c化简分离i
     
    Dp[j]-Dp[k]+(F[i]-F[k])*(2c+F[j]+F[k])
    -------------------------------------------<F[i](*)
                       2(F[j]-F[k])
     
    简化其为COM(j,k)<F[i]
    也就是说 ‘选j好过选k’当且仅当‘COM(j,k)<F[i]成立’
    所以如果一个队列的头依次为A,B 如果G(B,A)<=F[i] 那么把A删了吧
    代码们:
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<cstring>
     7 #define PAU putchar(' ')
     8 #define ENT putchar('
    ')
     9 using namespace std;
    10 const int maxn=50010;typedef long long LL;
    11 int deq[maxn];LL C[maxn],S[maxn],dp[maxn];
    12 double slope(int i,int j){return (dp[i]+S[i]*S[i]-dp[j]-S[j]*S[j])/(double)(S[i]-S[j]);}
    13 inline int read(){
    14     int x=0,sig=1;char ch=getchar();
    15     while(!isdigit(ch)){if(ch=='-')sig=-1;ch=getchar();}
    16     while(isdigit(ch))x=10*x+ch-'0',ch=getchar();
    17     return x*sig;
    18 }
    19 inline LL readl(){
    20     LL x=0,sig=1;char ch=getchar();
    21     while(!isdigit(ch)){if(ch=='-')sig=-1;ch=getchar();}
    22     while(isdigit(ch))x=10*x+ch-'0',ch=getchar();
    23     return x*sig;
    24 }
    25 inline void write(LL x){
    26     if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x;
    27     int len=0;LL buf[15];while(x)buf[len++]=x%10,x/=10;
    28     for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return;
    29 }
    30 int n,L;
    31 void init(){
    32     n=read();L=read();C[0]=S[0]=0;
    33     for(int i=1;i<=n;i++){C[i]=readl();C[i]+=C[i-1];S[i]=i+C[i];}
    34     return;
    35 }
    36 void work(){
    37     int s=0,e=0;dp[0]=deq[s]=0;
    38     for(int i=1;i<=n;i++){
    39         LL m=S[i]-L-1;
    40         while(s<e&&slope(deq[s+1],deq[s])<=(m<<1))++s;
    41         int j=deq[s];dp[i]=dp[j]+(m-S[j])*(m-S[j]);
    42         while(s<e&&slope(deq[e],deq[~-e])>=slope(i,deq[e]))--e;
    43         deq[++e]=i;
    44     }
    45     return;
    46 }
    47 void print(){
    48     write(dp[n]);
    49     return;
    50 }
    51 int main(){init();work();print();return 0;}
  • 相关阅读:
    线程
    unix架构
    Unix命令
    可重入函数reentrant function
    Eclipse 中 program arguments 与 VM arguments 的区别
    Java中Generics的使用
    Java的Reflection机制
    Java按值传递、按引用传递
    Java label
    LeetCode Merge Intervals
  • 原文地址:https://www.cnblogs.com/chxer/p/4644118.html
Copyright © 2011-2022 走看看