[HNOI2008] 玩具装箱

发布时间 2023-12-23 17:21:34作者: HL_ZZP

[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;
}