现在的位置: 首页 > 综合 > 正文

bsoj 2430 HNOI2008 玩具装箱(DP+斜率优化)

2013年10月23日 ⁄ 综合 ⁄ 共 1987字 ⁄ 字号 评论关闭

【HNOI2008】玩具装箱

 

Time Limit:10000MS  Memory Limit:65536K
Total Submit:288 Accepted:132 
Case Time Limit:1000MS

Description

  P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 
    x=j-i+Sigma(Ck) i<=K<=j 
  制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为x,其制作费用为(X-L)^2.其中L是一个 常量。P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过L。但他希望费用最小. 

Input

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

Output

  输出最小费用

Sample Input

  5 4
  3
  4
  2
  1
  4

Sample Output

  1

Source

xinyue

题目:http://mail.bashu.cn:8080/bs_oj/showproblem?problem_id=2430

题意:题目短,还是中文的。。。= =

分析:很容易想到一个状态转移方程f[ i ]=min{  f[ j-1 ] + ( i- j +w[ j , i ] - L)^2 } ,当然这个是要超时的O(n^2)

惯例,我们写详细的方程

f[ i ]=min{  f[ j-1 ] + ( i- j +w[ j , i ] - L)^2 } (1<=j<=i)

w[ l , r ]=c[ l ] + c [ l+1 ]  + ...+ c[ r ]

设: s[ i ]= sum{ c[ 1 ] + c [ 2 ]+ ... + c[ i ]}

那么有 

    ( i- j +w[ j , i ] - L)^2

= ( i- j + s[ i ] - s[ j-1 ] - L)^2

=[ ( i + s[i ] - L ) - ( j + s[ j- 1] ) ]^2   注:将与 j 无关的变量拿到一边,方面下面斜率优化

=( i + s[i ] - L )^2 - 2*( i + s[i ] - L ) * ( j + s[ j- 1] ) + ( j + s[ j- 1] )^2

还是照样可以YY出以下公式:

f[ i ]=min{ f[ j-1 ] + ( j + s[ j- 1] )^2  - 2*( i + s[i ] - L ) * ( j + s[ j- 1] ) } + ( i + s[i ] - L )^2 无关变量放外面

设: a=2*( i + s[i ] - L )    x=( j + s[ j- 1] )      y=f[ j-1 ] + ( j + s[ j- 1] )^2

则原式编程求函数 G=-ax +y的最小值,转换下成 y = ax + G

然后就是明显的斜率优化了。。。

PS:这题调试了好久,主要是边界的一些问题,不过一道题调试久了,正确率就高了,然后就1Y了

代码:

#include<cstdio>
#include<iostream>
using namespace std;
const int mm=55555;
typedef long long LL;
LL f[mm],s[mm];
int q[mm];
int i,j,n,l,r,L;
bool TRight(LL ax,LL ay,LL bx,LL by,LL cx,LL cy)
{
    return (ax-bx)*(cy-by)>=(ay-by)*(cx-bx);
}
LL gx(int i)
{
    return i+s[i-1];
}
LL gy(int i)
{
    return (i+s[i-1])*(i+s[i-1])+f[i-1];
}
LL get(int i,LL a)
{
    return gy(i)-a*gx(i);
}
int main()
{
    while(~scanf("%d%d",&n,&L))
    {
        for(i=1;i<=n;++i)
        {
            scanf("%d",&j);
            s[i]=s[i-1]+j;
        }
        for(i=1;i<=n;++i)f[i]=2e9;
        f[0]=l=0,r=-1;
        for(i=1;i<=n;++i)
        {
            while(l<r&&get(q[l],2*(i+s[i]-L))>=get(q[l+1],2*(i+s[i]-L)))++l;
            f[i]=f[i-1]+(s[i]-s[i-1]-L)*(s[i]-s[i-1]-L);
            if(l<=r)f[i]=min(f[i],get(q[l],2*(i+s[i]-L))+(i+s[i]-L)*(i+s[i]-L));
            while(l<r&&TRight(gx(q[r-1]),gy(q[r-1]),gx(q[r]),gy(q[r]),gx(i),gy(i)))--r;
            q[++r]=i;
        }
        printf("%I64d\n",f[n]);
    }
    return 0;
}
【上篇】
【下篇】