[HNOI2008] 玩具装箱
[HNOI2008] 玩具装箱
题目描述
P 教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。
P 教授有编号为 \(1 \cdots n\) 的 \(n\) 件玩具,第 \(i\) 件玩具经过压缩后的一维长度为 \(C_i\)。
为了方便整理,P教授要求:
-
在一个一维容器中的玩具编号是连续的。
-
同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物。形式地说,如果将第 \(i\) 件玩具到第 \(j\) 个玩具放到一个容器中,那么容器的长度将为 \(x=j-i+\sum\limits_{k=i}^{j}C_k\)。
制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为 \(x\),其制作费用为 \((x-L)^2\)。其中 \(L\) 是一个常量。P 教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过 \(L\)。但他希望所有容器的总费用最小。
输入格式
第一行有两个整数,用一个空格隔开,分别代表 \(n\) 和 \(L\)。
第 \(2\) 到 第 \((n + 1)\) 行,每行一个整数,第 \((i + 1)\) 行的整数代表第 \(i\) 件玩具的长度 \(C_i\)。
输出格式
输出一行一个整数,代表所有容器的总费用最小是多少。
样例 #1
样例输入 #1
5 4
3
4
2
1
4
样例输出 #1
1
提示
对于全部的测试点,\(1 \leq n \leq 5 \times 10^4\),\(1 \leq L \leq 10^7\),\(1 \leq C_i \leq 10^7\)。
题目很清晰,对是dp也没有什么隐藏
对是斜率优化也没什么隐藏。。毕竟这个结构的二次方都出来了,他甚至把代价的式子写给你了
设\(f[i]\)表示前\(i\)个玩具压缩完毕的最小代价,\(p[i]=i+SumC[i]\),\(cnt=L+1\)
\(f[i]=\displaystyle\min_{1\leq j < i}(f[j]+p[i]^2+p[j]^2+cnt^2+2\times p[i]\times p[j]-2\times cnt\times p[i]+2\times cnt\times p[j])\)
明显斜率优化
\(f[i]=f[j]+p[i]^2+p[j]^2+cnt^2-2\times p[i]\times p[j]-2\times cnt\times p[i]+2\times cnt\times p[j]\)
\(f[i]-cnt^2+2\times cnt\times p[i]-p[i]^2+2\times p[i]\times p[j]=f[j]+p[j]^2+2\times cnt\times p[j]\)
\(f[j]+p[j]^2+2\times cnt\times p[j]=2\times p[i]\times p[j]+f[i]-cnt^2+2\times cnt\times p[i]-p[i]^2\)
\(p[j]\)单调递增,\(j\)的范围单调移动,从1到\(i\),所以是最简单的斜率优化,秒了
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read() {
char c=getchar();int a=0,b=1;
for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
ll n,L,c[50001],SumC[50001],p[50001];
ll l,r,q[50001],f[50001],cnt;
inline ll Y(int j)
{
return f[j]+p[j]*p[j]+2*cnt*p[j];
}
inline ll X(int j)
{
return 2*p[j];
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n=read(),L=read();cnt=L+1;
for(int i=1;i<=n;i++)
{
c[i]=read();
SumC[i]=SumC[i-1]+c[i];
p[i]=SumC[i]+i;
}
l=r=1;
for(int i=1;i<=n;i++)
{
while(l<r&&(Y(q[l+1])-Y(q[l]))<=p[i]*(X(q[l+1])-X(q[l])))l++;
f[i]=f[q[l]]+(p[i]-p[q[l]]-cnt)*(p[i]-p[q[l]]-cnt);
while(l<r&&(Y(q[r])-Y(q[r-1]))*(X(i)-X(q[r]))>(Y(i)-Y(q[r]))*(X(q[r])-X(q[r-1])))r--;
q[++r]=i;
}
cout<<f[n]<<endl;
return 0;
}