bzoj1010: [HNOI2008]玩具装箱toy (斜率优化)

Solution

f [ i ] = m i n ( f [ j ] + ( i − j − 1 + s u m [ i ] − s u m [ j ] − L ) 2 ) f[i]=min(f[j]+(i-j-1+sum[i]-sum[j]-L)^2) f[i]=min(f[j]+(ij1+sum[i]sum[j]L)2)
为了方便计算,我们定义 a [ i ] = i + s u m [ i ] a[i]=i+sum[i] a[i]=i+sum[i] b [ i ] = i + s u m [ i ] + 1 + L b[i]=i+sum[i]+1+L b[i]=i+sum[i]+1+L

上式可转变为 f [ i ] = m i n ( f [ j ] + ( a [ i ] − b [ j ] ) 2 ) f[i]=min(f[j]+(a[i]-b[j])^2) f[i]=min(f[j]+(a[i]b[j])2)

因为 i i i 是通过 j j j 转移而得到的,假设 j j j 为最优解 f [ i ] = f [ j ] + ( a [ i ] − b [ j ] ) 2 f[i]=f[j]+(a[i]-b[j])^2 f[i]=f[j]+(a[i]b[j])2

f [ i ] = f [ j ] + a [ i ] 2 + b [ j ] 2 − 2 a [ i ] ⋅ b [ j ] f[i]=f[j]+a[i]^2+b[j]^2-2a[i]\cdot b[j] f[i]=f[j]+a[i]2+b[j]22a[i]b[j]

上式除了 f [ i ] f[i] f[i] 均为已知,我们将与 i i i 相关的整理到一起,得到 f [ j ] + b [ j ] 2 = 2 a [ i ] ⋅ b [ j ] + f [ i ] − a [ i ] 2 f[j]+b[j]^2=2a[i]\cdot b[j]+f[i]-a[i]^2 f[j]+b[j]2=2a[i]b[j]+f[i]a[i]2

此时可以理解为 f [ j ] + b [ j ] 2 f[j]+b[j]^2 f[j]+b[j]2 为因变量 ( y ) (y) (y) b [ j ] b[j] b[j] 为自变量 ( x ) (x) (x),则 2 ⋅ a [ i ] 2\cdot a[i] 2a[i] 为斜率。而想要 f [ i ] f[i] f[i] 最大,也就是截距最大。

那么我们定义点为 ( b [ i ] , f [ i ] + b [ i ] 2 ) (b[i],f[i]+b[i]^2) (b[i],f[i]+b[i]2)。想要截距最大,也就与次斜率相交最近的点即为答案。

所以我们要维护一个凸包(画图好麻烦啊…感性理解一波)

做法就是根据斜率,维护凸包。
首先看第一段斜率是否小于新加进来的这条的斜率,如果是,则把第一条便删去;
然后看最后一段斜率是不是大于新加进来的和倒数第二个点的斜率,如果是,则删去最后一个点。
注意:删点前提是有至少两个点。

注:前提是斜率单增…不然就需要二分了

Code

#include <cstdio>
#define ll long long
#define db double
const int N=50010;
int n,L,q[N];
db sum[N],c[N],f[N];
inline db a(int i){return i+sum[i];}
inline db b(int i){return a(i)+1+L;}
inline db X(int i){return b(i);}
inline db Y(int i){return f[i]+b(i)*b(i);}
inline db slope(int i,int j){return (Y(i)-Y(j))/(X(i)-X(j));}
int main(){
	freopen("bzoj1010.in","r",stdin);
	// freopen("a.out","w",stdout);
	scanf("%d%d",&n,&L);
	for(int i=1;i<=n;i++) {
		scanf("%lf",&c[i]); 
		sum[i]=sum[i-1]+c[i];
	}
	int h=1,t=1;
	for(int i=1;i<=n;i++){
		while(h<t && slope(q[h],q[h+1])<2*a(i)) h++;
		f[i]=f[q[h]]+(a(i)-b(q[h]))*(a(i)-b(q[h]));
		// printf("%lld %lld\n",X[i],Y[i]);
		while(h<t && slope(q[t],q[t-1])>slope(q[t-1],i)) t--;
		q[++t]=i;
		// printf("%d %lld\n",i,f[i]);
	}
	printf("%.0lf\n",f[n]);
	return 0;
} 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值