1. 程式人生 > >[bzoj 1010][HNOI 2008]玩具裝箱

[bzoj 1010][HNOI 2008]玩具裝箱

傳送門

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。但他希望費用最小.

Solution

斜率優化的練習題。

\(F_i=\min ({f_j+(sum_i-sum_j+i-j-l-1)^2})\)

我們令 \(g_i=sum_i+l\)

\(j<k\),且決策\(k\)優於決策\(j\)

\(\frac{((f_k+(g_k+l+1)^2)-(f_j+(g_j+l+1))^2 )}{ (g_k - g_j)}<=2*f_i\)


Code 

#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define MN 50005
int n,L;
ll f[MN],g[MN];
ll sqr(ll x){return x*x;}
int que[MN],l=1,r=0;
double calc(int j,int k)
{
    return (double)(f[j]+sqr(g[j]+L)-f[k]-sqr(g[k]+L))/(double)(g[j]-g[k]);
}
void insert(int x)
{
    for(;r>l&&calc(que[r],que[r-1])>=calc(x,que[r]);r--);
    que[++r]=x;
}
int get(int x)
{
    if(l>r) return 0;
    for(;r>l&&calc(que[l+1],que[l])<=(double)2*g[x];l++);
    return que[l];
}
int main()
{
    n=read();L=read()+1;
    register int i,j;
    for(i=1;i<=n;++i) g[i]=g[i-1]+read()+1;
    f[0]=que[++r]=0;
    for(i=1;i<=n;++i)
    {
        j=get(i);
        f[i]=f[j]+sqr(g[i]-g[j]-L);
        insert(i);
    }
    printf("%lld\n",f[n]);
}



Blog來自PaperCloud,未經允許,請勿轉載,TKS!