[BZOJ1010]玩具装箱

问题描述

8 月P 教授要去看奥运,但是他割舍不下自己的一大堆智力玩具。于是,他决定把所有玩具都运到北京去。P教授使用自己的物体维数压缩器ODZ(Object Dimension Zipper)来给玩具装箱。ODZ可以将任意物品变成一维,再装到一种特殊的一维容器中。P 教授有编号为1…N的N件玩具,第i 件玩具经过ODZ处理后一维长度是Ci。为了方便整理,P 教授要求在一个一维容器中的玩具编号是连续的。同时,如果一个一维容器中有多个玩具,那么相信两件玩具之间要加入1 个单位长度的填充物。形式地说,如果将第i 到第j 件玩具放在一个容器中 ( i < j ),那容器的长度将为

x=j−i+∑jk=iCk

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

数据输入

第一行输入两个整数N和L,接下来N行输入Ci。1<=N<=50000,1<=L、Ci<=10^7。

数据输出

输出最小费用。

样例输入

5 4
3
4
2
1
4

样例输出

1

题解:
sum[i] 表示 s i g m a ( k = 1 − &gt; i ) c [ k ] sigma( k = 1-&gt;i)c[k] sigma(k=1>ic[k]
d p [ i ] = m i n ( d p [ j ] + ( s u m [ i ] − s u m [ j ] + i − j − 1 − L ) 2 ) ( j &lt; i ) dp[i]=min(dp[j]+(sum[i]-sum[j]+i-j-1-L)^2) (j &lt; i) dp[i]=min(dp[j]+(sum[i]sum[j]+ij1L)2)(j<i)
f [ i ] = s u m [ i ] + i , c = 1 + L f[i]=sum[i]+i,c=1+L f[i]=sum[i]+i,c=1+L
d p [ i ] = m i n ( d p [ j ] + ( f [ i ] − f [ j ] − c ) 2 ) dp[i]=min(dp[j]+(f[i]-f[j]-c)^2) dp[i]=min(dp[j]+(f[i]f[j]c)2)
1.证明决策单调性
假设在状态i处的k决策优于j决策,即
d p [ k ] + ( f [ i ] − f [ k ] − c ) 2 &lt; = d p [ j ] + ( f [ i ] − f [ j ] − c ) 2 dp[k]+(f[i]-f[k]-c)^2&lt;=dp[j]+(f[i]-f[j]-c)^2 dp[k]+(f[i]f[k]c)2<=dp[j]+(f[i]f[j]c)2
则对于i后的所有状态t,要证明决策单调性
d p [ k ] + ( f [ t ] − f [ k ] − c ) 2 &lt; = d p [ j ] + ( f [ t ] − f [ j ] − c ) 2 dp[k]+(f[t]-f[k]-c)^2&lt;=dp[j]+(f[t]-f[j]-c)^2 dp[k]+(f[t]f[k]c)2<=dp[j]+(f[t]f[j]c)2
只要证
d p [ k ] + ( f [ i ] + v − f [ k ] − c ) 2 &lt; = d p [ j ] + ( f [ i ] + v − f [ j ] − c ) 2 dp[k]+(f[i]+v-f[k]-c)^2&lt;=dp[j]+(f[i]+v-f[j]-c)^2 dp[k]+(f[i]+vf[k]c)2<=dp[j]+(f[i]+vf[j]c)2
只要证
d p [ k ] + ( f [ i ] − f [ k ] − c ) 2 + 2 ∗ v ∗ ( f [ i ] − f [ k ] − c ) + v 2 &lt; = d p [ j ] + ( f [ i ] − f [ j ] − c ) 2 + 2 ∗ v ∗ ( f [ i ] − f [ j ] − c ) + v 2 dp[k]+(f[i]-f[k]-c)^2+2 * v * (f[i]-f[k]-c)+v^2&lt;=dp[j]+(f[i]-f[j]-c)^2+2 * v * (f[i]-f[j]-c)+v^2 dp[k]+(f[i]f[k]c)2+2v(f[i]f[k]c)+v2<=dp[j]+(f[i]f[j]c)2+2v(f[i]f[j]c)+v2
只要证
2 ∗ v ∗ ( f [ i ] − f [ k ] − c ) &lt; = 2 ∗ v ∗ ( f [ i ] − f [ j ] − c ) 2 * v * (f[i]-f[k]-c)&lt;=2* v * (f[i]-f[j]-c) 2v(f[i]f[k]c)<=2v(f[i]f[j]c)
f [ k ] &gt; = f [ j ] f[k]&gt;=f[j] f[k]>=f[j](显然)
证明完毕
2.求斜率方程
因为 d p [ k ] + ( f [ i ] − f [ k ] − c ) 2 &lt; = d p [ j ] + ( f [ i ] − f [ j ] − c ) 2 dp[k]+(f[i]-f[k]-c)^2&lt;=dp[j]+(f[i]-f[j]-c)^2 dp[k]+(f[i]f[k]c)2<=dp[j]+(f[i]f[j]c)2
展开
d p [ k ] + f [ i ] 2 − 2 ∗ f [ i ] ∗ ( f [ k ] + c ) + ( f [ k ] + c ) 2 &lt; = d p [ j ] + f [ i ] 2 − 2 ∗ f [ i ] ∗ ( f [ j ] + c ) + ( f [ j ] + c ) 2 dp[k]+f[i]^2-2 * f[i] * (f[k]+c)+(f[k]+c)^2 &lt;=dp[j]+f[i]^2-2 * f[i] *(f[j]+c)+(f[j]+c)^2 dp[k]+f[i]22f[i](f[k]+c)+(f[k]+c)2<=dp[j]+f[i]22f[i](f[j]+c)+(f[j]+c)2

d p [ k ] − 2 ∗ f [ i ] ∗ ( f [ k ] + c ) + ( f [ k ] + c ) 2 &lt; = d p [ j ] − 2 ∗ f [ i ] ∗ ( f [ j ] + c ) + ( f [ j ] + c ) 2 dp[k]-2 * f[i] * (f[k]+c)+(f[k]+c)^2&lt;=dp[j]-2 * f[i] * (f[j]+c)+(f[j]+c)^2 dp[k]2f[i](f[k]+c)+(f[k]+c)2<=dp[j]2f[i](f[j]+c)+(f[j]+c)2
( d p [ k ] + ( f [ k ] + c ) 2 − d p [ j ] − ( f [ j ] + c ) 2 ) / 2 ∗ ( f [ k ] − f [ j ] ) &lt; = f [ i ] (dp[k]+(f[k]+c)^2 -dp[j]-(f[j]+c)^2)/2 * (f[k]-f[j])&lt;=f[i] (dp[k]+(f[k]+c)2dp[j](f[j]+c)2)/2(f[k]f[j])<=f[i]
f[i]是单调递增的,我们使用队列维护一个下凸壳,每次取出队头作为决策 , 加入决策i时,令队尾为q[r],前一个为q[r-1] 满足斜率(q[r],i)<斜率(q[r-1],q[r])时,显然队尾是无效的,将其弹出

(题解来自hzwer http://hzwer.com/2114.html )

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LiangJiaJun main
#define INF 1999122700000000LL
using namespace std;
long long f[50004];
int n,L;
long long c[50004],a[50004];
long long q[50004];
long long SQR(long long m){return m * m ;}
double slop(int j,int k){
    return (f[k]-f[j]+SQR(a[k]+L)-SQR(a[j]+L))/(2.0*(a[k]-a[j]));
}
int t,w;
int LiangJiaJun (){
    for(int i=0;i<=50001;i++)f[i]=INF;
    f[0]=0;
    scanf("%d%d",&n,&L);
    a[0]=0;++L;
    for(int i=1;i<=n;i++){
        scanf("%lld",&c[i]);
        a[i]=a[i-1]+c[i];
    }
    for(int i=1;i<=n;i++)a[i]+=(long long)i;
    t=w=1;q[w]=0;
    for(int i=1;i<=n;i++){
        while(t<w && slop(q[t],q[t+1]) <= a[i]) ++t;
        int last = q[t];
        f[i]=f[last]+SQR(a[i]-a[last]-L);
        while(t<w && slop(q[w],i) <= slop(q[w-1],q[w])) w--;
        q[++w]=i;
    }
    cout<<f[n]<<endl;
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值