玩具装箱 [HNOI2008] (NLOGN)

来源:互联网 发布:手机网络3d游戏排行榜 编辑:程序博客网 时间:2024/05/08 16:06

题目地址请点击——


Toy


Description

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


Input

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


Output

输出最小费用


Sample Input

5 4
3
4
2
1
4


Sample Output

1


Solution

f(x) 表示前 x 个玩具的最小费用。

f(x)=minx1i=1{f(i)+w[i+1,x]}
其中
w[i,j]=(ji+k=1jc[k]L)2

打表发现满足决策单调性,优化到 O(nLogn)


Code

#include <iostream>#include <cstdio>#define LL long long#define k s[end][0]#define tpm (s[top][1]-i-1+c[s[top][1]]-c[i]-l)#define mpt (s[top][1]-s[top][0]-1+c[s[top][1]]-c[s[top][0]]-l)#define tpm2 (s[top-1][1]-i-1+c[s[top-1][1]]-c[i]-l)#define mpt2 (s[top-1][1]-s[top-1][0]-1+c[s[top-1][1]]-c[s[top-1][0]]-l)#define Max(x,y) ((x)>(y)?(x):(y))#define Min(x,y) ((x)<(y)?(x):(y))using namespace std;LL n,l,top=0,end=0;LL c[50010];LL s[50010][3];LL f[50010];bool judge(LL x){    LL now=s[top][0];    LL pre=s[top-1][0];    return (f[now]+(x-now-1+c[x]-c[now]-l)*(x-now-1+c[x]-c[now]-l)<=f[pre]+(x-pre-1+c[x]-c[pre]-l)*(x-pre-1+c[x]-c[pre]-l));}LL find(LL l,LL r){    LL ans=2147483647;    while(l<=r){        LL mid=(l+r)/2;        if(judge(mid)){            ans=Min(ans,mid);            if(r!=mid-1)r=mid-1;            else break;        }        else{            if(l!=mid+1)l=mid+1;            else break;        }    }    return ans;}int main(){    scanf("%lld%lld",&n,&l);    for(LL i=1;i<=n;i++){        LL x;        scanf("%lld",&x);        c[i]=c[i-1]+x;    }    f[0]=0;    end=1;    s[++top][0]=0;s[top][1]=1;s[top][2]=n;    for(LL i=1;i<=n;i++){        while(i>s[end][2])end++;        LL tmp=(i-k-1+c[i]-c[k]-l);        f[i]=f[k]+tmp*tmp;        if(s[top][1]>i&&f[i]+tpm*tpm<=f[s[top][0]]+mpt*mpt){            s[top][0]=i;            while(top>1&&f[i]+tpm2*tpm2<=f[s[top-1][0]]+mpt2*mpt2){                s[--top][0]=i;                s[top][2]=s[top+1][2];            }            if(top>1)s[top-1][2]=s[top][1]-1;        }        else{            s[++top][0]=i;            s[top][2]=n;        }        if(top>1){            s[top][1]=find(Max(i+1,s[top-1][1]+1),n);            s[top-1][2]=s[top][1]-1;        }    }    printf("%lld\n",f[n]);    return 0;}
0 0
原创粉丝点击