• [bzoj1010][HNOI2008]玩具装箱


    Description

    n个物品,每个物品长度为c_i,现在要把这n个物品划分成若干组,每组中的物品编号是连续的,规定每组的长度x=j-i+sum_{k=i}^{j}c_k,费用为(x-l)^2,求最小费用.

    Input

    第一行输入两个整数nl,接下来n行输入c_i.

    Output

    一行表示最小费用.

    Sample Input

    5 4

    3

    4

    2

    1

    4

    Sample Output

    1

    HINT

    1;leq;n;leq;50000,1;leq;l,c_i;leq;10^7

    Solution

    f[i]表示将前i个物品分组所需最小费用.

    f[i]=min{f[j]+(i-j-1+sum[i]-sum[j]-l)^2}(j<i)

    O(n^2)T,考虑斜率优化.

    k>jf[i]_k<f[i]_j时,

    f[i]_j=f[j]+(i-j-1+sum[i]-sum[j]-l)^2

    f[i]_k=f[k]+(i-k-1+sum[i]-sum[k]-l)^2

    尽量将i,j分离,设g(j)=j+sum[j],h(i)=i+sum[i]-1-l,得

    f[i]_j=f[j]+(h(i)-g(j))^2

    f[i]_k=f[k]+(h(i)-g(k))^2

    f[i]_k<f[i]_j的前提是

    f[k]-f[j]+(h(i)-g(k))^2-(h(i)-g(j))^2<0

    整理得frac{(f[k]+g(k)^2)-(f[j]+g(j)^2)}{g(k)-g(i)}<2;	imes;h(i)

    T(j_1,j_2)=frac{(f[j_2]+g(j_2)^2)-(f[j_1]+g(j_1)^2)}{g(j_2)-g(j_1)}

    T(j_1,j_2)<T(j_2,j_3)<...

    (若存在T(j_{n-1},j_n)>T(j_n,j_{n+1}),因为h(i)单调递增,所以j_{n+1}一定比j_n优,即j_n可以删去)

    所以每次取元素时,将满足T(j_n,j_{n+1})<2;	imes;h(i)j_n出队(因为j_{n+1}j_n优),然后取队首为j.

    #include<set> 
    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 50001
    using namespace std;
    typedef long long ll;
    ll f[N],s[N],q[N],h,t,l,n;
    inline ll sqr(ll k){
        return k*k;
    }
    inline ll x(ll k){
        return k+s[k];
    }
    inline ll y(ll k){
        return f[k]+sqr(x(k));
    }
    inline double cmp(ll p,ll q){
        return (double)(y(q)-y(p))/(double)(x(q)-x(p));
    }
    inline ll g(ll k){
        return k+s[k]-l;
    }
    inline void init(){
        scanf("%lld%lld",&n,&l);
        for(ll i=1;i<=n;i++){
            scanf("%lld",&s[i]);
            s[i]+=s[i-1];
        }
        for(ll i=1,k;i<=n;i++){
            k=g(i)<<1;
            while(h<t&&cmp(q[h],q[h+1])<k) h++;
            f[i]=f[q[h]]+sqr(x(q[h])-g(i)+1);
            while(h<t&&cmp(q[t],i)<cmp(q[t-1],q[t]))
                t--;
            q[++t]=i;
        }
        printf("%lld
    ",f[n]);
    }
    int main(){
        freopen("toy.in","r",stdin);
        freopen("toy.out","w",stdout);
        init();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    CMDB表结构设计
    mysql数据库密码
    web之提取状态码
    ELK的启动脚本
    ELK的轻量级搭建使用
    liunx安装JDK
    liunx的urandom生成随机字符
    vim快捷键
    升级系统的python程序
    Mysql的进阶小记
  • 原文地址:https://www.cnblogs.com/AireenYe/p/5963014.html
Copyright © 2020-2023  润新知