[HNOI2008]玩具装箱TOY

题目描述

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。但他希望费用最小.

输入输出格式

输入格式:

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

输出格式:

输出最小费用

输入输出样例

输入样例#1:
5 4
3
4
2
1
4
输出样例#1:
1

题解:
上题一样的套路哈.直接写出原始dp方程,f[i]=f[j]+(sum[i]-sum[j]+i-j-L-1)^2
但是天真的小朋友,千万把后面一块全拆.分i,j两部分即可
变为f[i]=f[j]+((sum[i]+i-L-1)+(-j-sum[j]))^2 然后开平方
最后变为斜率优化的标准形式:
(f[j]-f[k]+(j+sum[j])^2-(k+sum[k])^2)/(2*((-k-sum[k])-(-j-sum[j])))<=(sum[i]+i-L-1)
那么(sum[i]+i-L+1)就是当前直线斜率,
(f[j]-f[k]+(j+sum[j])^2-(k+sum[k])^2)就是y,(2*((-k-sum[k])-(-j-sum[j])))就是x.
直接维护凸壳即可 代码好写
 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 using namespace std;
 8 typedef long long ll;
 9 const int N=50005;
10 ll sum[N];
11 int gi(){
12     int str=0;char ch=getchar();
13     while(ch>'9' || ch<'0')ch=getchar();
14     while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
15     return str;
16 }
17 int n,m,q[N];ll f[N];
18 ll fy(int i,int j){
19     return f[i]+(i+sum[i])*(i+sum[i])-f[j]-(j+sum[j])*(j+sum[j]);
20 }
21 ll fx(int i,int j){
22     return ((-(-i-sum[i])+(-j-sum[j]))<<1);
23 }
24 void work(){
25     n=gi();m=gi();
26     for(int i=1,x;i<=n;i++)x=gi(),sum[i]=sum[i-1]+x;
27     int l=1,r=1,j,k;q[1]=0;
28     for(int i=1;i<=n;i++){
29         while(l<=r-1){
30             j=q[l];k=q[l+1];
31             if(fy(j,k)>=fx(j,k)*(sum[i]+i-m-1))l++;
32             else break;
33         }
34         f[i]=f[q[l]]+(sum[i]-sum[q[l]]+i-q[l]-1-m)*(sum[i]-sum[q[l]]+i-q[l]-1-m);
35         while(l<=r-1){
36             j=q[r];k=q[r-1];
37             if(fy(i,j)*fx(j,k)<=fx(i,j)*fy(j,k))r--;
38             else break;
39         }
40         q[++r]=i;
41     }
42     printf("%lld
",f[n]);
43 }
44 int main()
45 {
46     work();
47     return 0;
48 }