zoukankan      html  css  js  c++  java
  • bzoj1010 [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

    这道题不限箱子的数目,所以一维就够了(终于是一维了,受不了二维)
    f[i]=f[j]+((i-j-1+sum[i]-sum[j])-L)^2

    斜率优化

    画柿子演示:
    设k < j < i,转移点j比k更优
    则有:
    这里写图片描述

    斜率的形式我们有了
    g[j][k] < i+sum[i]
    表示j比k优

    关键点
    g[i][j] < g[j][k]
    j点不可能作为转移点

    主要操作:
    1.维护一个双端对列
    2.在转移的时候,如果队列中依次有a,b,c等元素
    若g[b][a] < sum[i]+i,a出队
    直到g[x][y]>=sum[i]+i
    从队首转移
    3.入队的时候,如果队列中依次有a,b,c等元素,入队元素为d
    若g[d][c] < g[c][b] ,c出对
    直到g[d][x]>=g[x][y] ,d入队

    tip

    不用特殊计算f[1]的值,
    直接在循环里维护就行了(这样既可以维护f,也可以入队)

    我这个zz
    在写转移方程的时候竟然忘了累加

    f[i]=f[q[tou]]+sqr(i-q[tou]+sum[i]-sum[q[tou]]-L);

    我发现只要是牵扯到L,用到的都是L+1,所以我干脆在一开始的时候就L++

    这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #define ll long long
    
    using namespace std;
    
    const int N=50010;
    int n,q[N],tou,wei;
    ll l,a[N],f[N];
    
    ll sqr(ll x)
    {
        return x*x;
    }
    
    double get(int j,int k)
    {
        double x1=(double)f[j]+sqr(j+a[j])+2*l*(j+a[j]);
        double x2=(double)f[k]+sqr(k+a[k])+2*l*(k+a[k]);
        double x3=(double)2*(j+a[j]-k-a[k]);
        return (double)(x1-x2)/x3;
    }
    
    void doit()
    {
        int i,j;
        tou=wei=0;
        for (i=1;i<=n;i++)
        {
            while (tou<wei&&get(q[tou+1],q[tou])<=i+a[i]) tou++;
            f[i]=f[q[tou]]+sqr((i-q[tou]+a[i]-a[q[tou]])-l);
            while (tou<wei&&get(i,q[wei])<=get(q[wei],q[wei-1])) wei--;
            q[++wei]=i;
        }
        printf("%lld",f[n]);
    }
    
    int main()
    {
        scanf("%d%lld",&n,&l);
        l++;
        for (int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]+=a[i-1];
        doit();
        return 0;
    }
  • 相关阅读:
    weui-switch开关控件,表单提交后如何取值
    [转]判断存储过程、触发器、视图是否存在并删除
    修改服务器的3389端口
    如何在react-native 中优雅的使用 redux
    react native js 与 native 的通信与交互方式
    对 JS virtual DOM 的一知半解
    Python的实例方法,类方法,静态方法之间的区别及调用关系
    redux 管理你的 react 应用
    react- native 入门
    git 指南
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673153.html
Copyright © 2011-2022 走看看