Toy
Description
P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。
他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。
P教授有编号为
1...N
的
N
件玩具,第
为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。
同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第
i
件玩具到第
制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为
x
,其制作费用为
其中
L
是一个常量。
P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过
但他希望费用最小.
Input
第一行输入两个整数
N
,
接下来
N
行输入
1<=N<=50000
,
1<=L,Ci<=107
Output
输出最小费用
Sample Input
5 4
3
4
2
1
4
Sample Output
1
Solution
设
f(x)
表示前
x
个玩具的最小费用。
打表发现满足决策单调性,优化到 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;
}