zoukankan      html  css  js  c++  java
  • BZOJ-1010-[HNOI2008]玩具装箱toy(斜率优化)

    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
     

    题解

    这道题朴素dp要O(n^2),果断超时,dp[i]表示前1~i合并的最优值,枚举j表示前一次合并的位置

    那么dp[i]=min(dp[i],dp[j]+(i-(j+1)+s[i]-s[j]-L)^2)

    这里可以用斜率优化来做,把复杂度降到O(n)

    我们假设k<j<i,j比k更优,那么就是dp[j]+(i-(j+1)+s[i]-s[j]-L)^2<=dp[k]+(i-(k+1)+s[i]-s[k]-L)^2

    我们这里再用f[i]=s[i]+i,那么式子化成了dp[j]+(f[i]-f[j]-1-L)^2<=dp[k]+(f[i]-f[k]-1-L)^2

    再接着化下去就变成了

    (dp[j]-dp[k]+(f[j]+1+L)^2-(f[k]+1+L)^2)/(2*(f[j]-f[k]))<=f[i]

    根据这个式子,我们在加入队列的时候就可以判断了

    对于踢出队尾,我们考虑一下q[tail],i和q[tail-1],q[tail]的斜率

    因为f[i]是单调递增的,q[tail-1],q[tail]原来就满足<=f[i],所以要踢出队尾,就要有q[tail],i<q[tail-1],q[tail](表示i比q[tail]更优)

     1 #include<bits/stdc++.h>
     2 #define N 50005
     3 #define ll long long
     4 using namespace std;
     5 int n,head,tail;
     6 ll L;
     7 int a[N];
     8 ll s[N],f[N],dp[N],q[N];
     9 double calc(int k,int j){
    10     return (double)(dp[j]-dp[k]+(f[j]+1+L)*(f[j]+1+L)-(f[k]+1+L)*(f[k]+1+L))/(2*(f[j]-f[k]));
    11 }
    12 int main(){
    13     scanf("%d%lld",&n,&L);
    14     for (int i=1;i<=n;i++)
    15         scanf("%lld",&a[i]),f[i]=f[i-1]+1+a[i];
    16     head=1; tail=1;
    17     for (int i=1;i<=n;i++){
    18         while (head<tail&&calc(q[head],q[head+1])<=f[i]) head++;
    19         int k=q[head];
    20         dp[i]=dp[k]+(f[i]-f[k]-1-L)*(f[i]-f[k]-1-L);
    21         while (head<tail&&calc(q[tail],i)<calc(q[tail-1],q[tail])) tail--;
    22         q[++tail]=i;
    23     } 
    24     printf("%lld
    ",dp[n]);
    25     return 0;
    26 }
    View Code
  • 相关阅读:
    记录ViewPager配合Fragment使用中遇到的一个问题
    StringBuffer类的构造方法
    认识StringBuffer类
    Java中增强for循环的用法
    xml解析案例
    XML的序列化(Serializer)
    文件权限之(介绍,更改,扩展)
    保存数据到sdcard中去
    反编译
    后端——框架——容器框架——spring_core——格式化器
  • 原文地址:https://www.cnblogs.com/zhuchenrui/p/7631173.html
Copyright © 2011-2022 走看看