洛谷P3195 [HNOI2008] 玩具装箱

洛谷P3195 [HNOI2008] 玩具装箱

题目描述

P 教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。

P 教授有编号为 1⋯n1 \cdots n1nnnn 件玩具,第 iii 件玩具经过压缩后的一维长度为 CiC_iCi

为了方便整理,P 教授要求:

  • 在一个一维容器中的玩具编号是连续的。

  • 同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物。形式地说,如果将第 iii 件玩具到第 jjj 个玩具放到一个容器中,那么容器的长度将为 x=j−i+∑k=ijCkx=j-i+\sum\limits_{k=i}^{j}C_kx=ji+k=ijCk

制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为 xxx,其制作费用为 (x−L)2(x-L)^2(xL)2。其中 LLL 是一个常量。P 教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过 LLL。但他希望所有容器的总费用最小。

输入格式

第一行有两个整数,用一个空格隔开,分别代表 nnnLLL

222 到 第 (n+1)(n + 1)(n+1) 行,每行一个整数,第 (i+1)(i + 1)(i+1) 行的整数代表第 iii 件玩具的长度 CiC_iCi

输出格式

输出一行一个整数,代表所有容器的总费用最小是多少。

样例 #1

样例输入 #1

5 4
3
4
2
1
4

样例输出 #1

1

提示

对于全部的测试点,1≤n≤5×1041 \leq n \leq 5 \times 10^41n5×1041≤L≤1071 \leq L \leq 10^71L1071≤Ci≤1071 \leq C_i \leq 10^71Ci107

问题介绍

有的题目的转移方程并不如我们所预期的样式,而是形如dpi=max/min(a[i]⋅b[j]+c[i]+d[j])dp_i=max/min(a[i]\cdot b[j]+c[i]+d[j])dpi=max/min(a[i]b[j]+c[i]+d[j])的形式,单调队列优化不再成立,我们需要找到新的优化方式解决。

以玩具装箱的背景理解斜率优化

式子处理

因为有∑Ci\sum C_iCi的存在,所以前缀和是必然的,特别注意的一点就是我们不妨将填充物的长度计入物体长度,计算总和时减111即可。即令Si=∑i=1n(Ci+1)S _i=\sum\limits_{i=1}^{n}(C_i+1)Si=i=1n(Ci+1)

dpidp_idpi表示装好前iii个玩具的最小花费,则有dpi=minj∈[0,i−1](dpj+(Si−Sj−1−L)2)dp_i=\mathop{min}\limits_{j\in[0,i-1]}(dp_j+(S_i-S_j-1-L)^2)dpi=j[0,i1]min(dpj+(SiSj1L)2)

方便拆括号,于是可以令L′=L+1L'=L+1L=L+1,则dpi=minj∈[0,i−1](dpj+(Si−Sj−L′)2)dp_i=\mathop{min}\limits_{j\in[0,i-1]}(dp_j+(S_i-S_j-L')^2)dpi=j[0,i1]min(dpj+(SiSjL)2)

方便接下来化简,我们写作dpi=minj∈[0,i−1](dpi,j),dpi,j=dpj+(Si−Sj−L′)2dp_i=\mathop{min}\limits_{j\in[0,i-1]}(dp_{i,j}),dp_{i,j}=dp_j+(S_i-S_j-L')^2dpi=j[0,i1]min(dpi,j),dpi,j=dpj+(SiSjL)2

注意到在dpidp_idpi的更新中,iii始终不变,在转移过程中可以消掉,于是我们将上式尽可能的将这一部分分解出来。

dpi,j=Si2+dpj−2SiSj−2SiL′+(Sj+L′)2dp_{i,j}=S_i^2+dp_j-2S_iS_j-2S_iL'+(S_j+L')^2dpi,j=Si2+dpj2SiSj2SiL+(Sj+L)2

接下来要比较哪个策略更优,于是我们假设存在j1<j2j_1<j_2j1<j2dpi,j1≥dpi,j2dp_{i,j_1}\ge dp_{i,j_2}dpi,j1dpi,j2

Si2+dpj1−2SiSj1−2SiL′+(Sj1+L′)2≥Si2+dpj2−2SiSj2−2SiL′+(Sj2+L′)2S_i^2+dp_{j_1}-2S_iS_{j_1}-2S_iL'+(S_{j_1}+L')^2\ge S_i^2+dp_{j_2}-2S_iS_{j_2}-2S_iL'+(S_{j_2}+L')^2Si2+dpj12SiSj12SiL+(Sj1+L)2Si2+dpj22SiSj22SiL+(Sj2+L)2

dpj1−2SiSj1+(Sj1+L′)2≥dpj2−2SiSj2+(Sj2+L′)2dp_{j_1}-2S_iS_{j_1}+(S_{j_1}+L')^2\ge dp_{j_2}-2S_iS_{j_2}+(S_{j_2}+L')^2dpj12SiSj1+(Sj1+L)2dpj22SiSj2+(Sj2+L)2

根据前面的规定,在这个式子中,jjj是变量,iii是参数,但是我们没必要直接算出j1,j2j_1,j_2j1j2iii的关系,只需要简单的分离一下就行了。

2Si(Sj2−Sj1)≥dpj2−dpj1+(Sj2+L′)2−(Sj1+L′)22S_i(S_{j_2}-S_{j_1})\ge dp_{j_2}-dp_{j_1}+(S_{j_2}+L')^2-(S_{j_1}+L')^22Si(Sj2Sj1)dpj2dpj1+(Sj2+L)2(Sj1+L)2

这里SSS是前缀和,这就意味着在输入均为正的情况下Sj2−Sj1≥0S_{j_2}-S_{j_1}\ge 0Sj2Sj10,于是可以进行下一步分离

2Si≥(dpj2+(Sj2+L′)2)−(dpj1+(Sj1+L′)2)Sj2−Sj12S_i\ge \frac{(dp_{j_2}+(S_{j_2}+L')^2)-(dp_{j_1}+(S_{j_1}+L')^2)}{S_{j_2}-S_{j_1}}2SiSj2Sj1(dpj2+(Sj2+L)2)(dpj1+(Sj1+L)2)

这个两值之差的比很容易让人联想到斜率kkk(这就是这种优化叫做斜率优化的原因)。

处理斜率

我们设对于dpi,jdp_{i,j}dpi,j,在平面直角坐标系上有一个点Pj(Sj,dpj+(Sj+L’)2)P_{j}(S_j,dp_j+(S_j+L’)^2)Pj(Sj,dpj+(Sj+L)2)

根据上述结论,点Pj2P_{j_2}Pj2优于Pj1P_{j_1}Pj1当且仅当ΔyΔx≤2Si\frac{\Delta y}{\Delta x}\le2S_iΔxΔy2Si,否则Pj1P_{j_1}Pj1更优。

此时dpi,jdp_{i,j}dpi,j可以写作Yj−2Xj+Si−2SiL′Y_j-2X_j+S_i-2S_iL'Yj2Xj+Si2SiL

接下来从坐标系上看多个点之间的关系,如图所示:

在这里插入图片描述

记图中的点A:Pj1   B:Pj2   C:Pj3A:P_{j_1} \space\space\space B:P_{j_2}\space\space\space C:P_{j_3}A:Pj1   B:Pj2   C:Pj3方便处理,不妨设k1>k2k_1> k_2k1>k2

同时设2Si=k02S_i=k_02Si=k0,即刚刚计算得到的分界线。

对于k1k_1k1k2k_2k2本身,可以以它们分别与k0k_0k0的关系为划分依据分类讨论。

(1)\mathbb{(1)}(1)k1≤k0k_1\le k_0k1k0时,j2j_2j2优于j1j_1j1,反之当k1>k0k_1>k_0k1>k0时,j1j_1j1优于j2j_2j2

(2)\mathbb{(2)}(2)k2≤k0k_2\le k_0k2k0时,j3j_3j3优于j2j_2j2,反之当k1>k0k_1>k_0k1>k0时,j2j_2j2优于j3j_3j3

接下来将k1,k2,k0k_1,k_2,k_0k1,k2,k0的关系放在一起讨论,因为前面k1>k2k_1> k_2k1>k2确定,所以有三种情况:

(1)\mathbb{(1)}(1)k0<k2<k1k_0<k_2<k_1k0<k2<k1时,j1j_1j1优于j2j_2j2优于j3j_3j3,此时取j1j_1j1

(2)\mathbb{(2)}(2)k2≤k0<k1k_2\le k_0<k_1k2k0<k1时,j1j_1j1优于j2j_2j2j3j_3j3优于j2j_2j2,此时取j1j_1j1j3j_3j3

(3)\mathbb{(3)}(3)k2<k1≤k0k_2<k_1\le k_0k2<k1k0时,j3j_3j3优于j2j_2j2优于j1j_1j1,此时取j3j_3j3

综上,容易发现无论如何都不会取j2j_2j2,于是我们可以直接忽略BBB点,如图所示:

在这里插入图片描述

经过一系列这样的删点操作,我们得到了一个图像。

在这里插入图片描述

容易发现,斜率是递增的,因为当一个点插入后不满足斜率递增就会被删除(即图中的LLL点)。

同时我们知道,当kj≤k0=2Sik_j\le k_0=2S_ikjk0=2Si时,最优点在jmaxj_{max}jmax取到;当k0<kjk_0<k_jk0<kj时,最优点在jminj_{min}jmin取到,于是我们需要找到第一个满足kj≥k0k_j\ge k_0kjk0的一段直线,其左端点恰好是最优解。又回到单调性问题,因为SiS_iSi单增,相邻斜率亦单增,所以可以用单调队列解决。

代码

注意到数据范围会超intintint,所以不开long longlong \ longlong long__ __ __。

另外kkk值可能是小数,不仅要开doubledoubledouble,还要$$

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

typedef long long LL;

const int N=5e4+10;

LL n,L;
long double s[N];
LL dp[N];
LL q[N],l,r;

long double k(int a,int b)
{
	return ((dp[a]+(s[a]+L)*(s[a]+L))-(dp[b]+(s[b]+L)*(s[b]+L)))/(s[a]-s[b]);
}

int main()
{
	cin>>n>>L;
	L++;
	for(int i=1;i<=n;i++)
	{
		cin>>s[i];
		s[i]+=s[i-1]+1;
	}
	l=1,r=1;
	for(int i=1;i<=n;i++)
	{
		while(l<r&&k(q[l],q[l+1])<2*s[i])
			l++;
		dp[i]=dp[q[l]]+(s[i]-s[q[l]]-L)*(s[i]-s[q[l]]-L);
		while(l<r&&k(q[r],q[r-1])>=k(q[r-1],i))
			r--;
		q[++r]=i;
	}
	cout<<dp[n]<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值