P3195 [HNOI2008]玩具装箱

题目

题目

思路

来纪中第一题,献给斜率优化dp大法,dpnb!!!
论与wyc和xjq住在一个宿舍是什么感受


本题解也许会详细一点
实际上本题属于一个计算几何题……
先来个暴力方程,设 S i = ∑ j = 1 i ( C i + 1 ) S_i=\sum_{j=1}^i(C_i+1) Si=j=1i(Ci+1),又设 f i f_i fi为前i个中的最优解,则有:
f i = m i n ( f j + ( S i − S j − 1 − L ) 2 ) ( 1 < = j < i ) f_i=min(f_j+(S_i-S_j-1-L)^2)(1<=j<i) fi=min(fj+(SiSj1L)2)(1<=j<i)
n方暴力,T到飞起
显然这范围只允许nlogn及以内时间复杂度算法,dp显然在与数据结构没关系的前提下和log也是没关系的,而输入就O(n)了,所以我们的dp算法是O(n)的。
O(n)dp=单调队列优化
单调队列优化+方程中的乘法运算=斜率优化
于是到了美丽的式子时间:
j 1 , j 2 ( 1 < = j 1 < j 2 < i ) j_1,j_2(1<=j1<j2<i) j1,j2(1<=j1<j2<i)为2个决策点,若 j 2 j_2 j2优于 j 1 j_1 j1,当且仅当:
f j 2 − 2 S i S j 2 + ( S j 2 + L ) 2 < = f j 1 − 2 S i S j 1 + ( S j 1 + L ) 2 f_{j_2}-2S_iS_{j_2}+(S_{j_2}+L)^2<=f_{j_1}-2S_iS_{j_1}+(S_{j_1}+L)^2 fj22SiSj2+(Sj2+L)2<=fj12SiSj1+(Sj1+L)2
移项得:
− 2 S i ( S j 2 − S j 1 ) < = f j 1 − f j 2 + ( S j 1 + L ) 2 − ( S j 2 + L ) 2 -2S_i(S_{j_2}-S_{j_1})<=f_{j_1}-f_{j_2}+(S_{j_1}+L)^2-(S_{j_2}+L)^2 2Si(Sj2Sj1)<=fj1fj2+(Sj1+L)2(Sj2+L)2
显然 S j 2 − S j 1 > 0 S_{j_2}-S_{j_1}>0 Sj2Sj1>0,所以有:
2 S i > = ( f j 1 + ( S j 1 + L ) 2 ) − ( f j 2 + ( S j 2 + L ) 2 ) S j 2 − S j − 1 2S_i>={{(f_{j_1}+(S_{j_1}+L)^2)-(f_{j_2}+(S_{j_2}+L)^2)}\over{S_{j_2}-S_{j-1}}} 2Si>=Sj2Sj1(fj1+(Sj1+L)2)(fj2+(Sj2+L)2)
斜率方程构造完成,本题解决
code:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
long long n,L,q[50004],f[50004],x,s[50004],h=1,t=1;
long long Y(int x)
{
	return f[x]+(s[x]+L)*(s[x]+L);
}
long long X(int x)
{
	return s[x];
}
long double u(int x,int y)
{
	return (long double)(Y(y)-Y(x))/(X(y)-X(x));
}
int main()
{
	scanf("%lld%lld",&n,&L);
	++L;
	for (int i=1;i<=n;i++)
	{
		scanf("%lld",&x);
		s[i]=s[i-1]+x+1;
	}
	for (int i=1;i<=n;i++)
	{
		while (h<t&&u(q[h],q[h+1])<2*s[i]) h++;
		f[i]=f[q[h]]+(s[i]-s[q[h]]-L)*(s[i]-s[q[h]]-L);
		while (h<t&&u(q[t-1],i)<u(q[t-1],q[t])) t--;
		q[++t]=i;
	}
	printf("%lld\n",f[n]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值