[斜率优化]BZOJ 1096——仓库建设

来源:互联网 发布:办公室电话网络布线 编辑:程序博客网 时间:2024/05/22 11:46

1096: [ZJOI2007]仓库建设

题目描述

  L公司有N个工厂,由高到底分布在一座山上。如图所示,工厂1在山顶,工厂N在山脚。由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用。突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏。由于地形的不同,在不同工厂建立仓库的费用可能是不同的。第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库的费用是Ci。对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏,而由于L公司产品的对外销售处设置在山脚的工厂N,故产品只能往山下运(即只能运往编号更大的工厂的仓库),当然运送产品也是需要费用的,假设一件产品运送1个单位距离的费用是1。假设建立的仓库容量都都是足够大的,可以容下所有的产品。你将得到以下数据:1:工厂i距离工厂1的距离Xi(其中X1=0);2:工厂i目前已有成品数量Pi;3:在工厂i建立仓库的费用Ci;请你帮助L公司寻找一个仓库建设的方案,使得总的费用(建造费用+运输费用)最小。

解题思路

根据题目描述不难想到是DP,很快就会推出方程

f[i]=min(f[j]+c[i]+k=j+1i(x[i]x[k])p[k])

如果提前构造数组d[]成品数量的前缀和,w[]位置和成品数量的前缀和,那么转移方程会变的明显
f[i]=min(f[j]+c[i]+x[i](d[i]d[j])(w[i]w[j]))

把无关项移出来
f[i]=min(f[j]x[i]d[j]+w[j])+x[i]d[i]w[i]+c[i]

k=x[i],x=d[j],y=f[j]+w[j]
通过b=kx+y,y=kx+b

接下来套用斜率优化就可以了。

#include<cstdio>#include<cstring>#include<algorithm>#define LL long longusing namespace std;const int maxn=1000005;int n,now,til;LL x[maxn],s_p[maxn],s_xp[maxn],f[maxn],c[maxn];struct jz{    LL x,y;    jz(LL a=0,LL b=0):x(a),y(b){}    jz operator-(const jz &b){return jz(x-b.x,y-b.y);}}a[maxn];inline int _read(){    int num=0;char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();    return num;}LL getb(jz x,LL k){return -k*x.x+x.y;}LL check(jz x,jz y){return x.x*y.y-x.y*y.x;}int main(){    freopen("exam.in","r",stdin);    freopen("exam.out","w",stdout);    n=_read();    for (int i=1;i<=n;i++){        x[i]=_read();int p=_read();c[i]=_read();        s_p[i]=s_p[i-1]+p;s_xp[i]=s_xp[i-1]+x[i]*p;    }    memset(f,63,sizeof(f));    f[0]=0;now=til=1;a[1]=jz(0,0);    for (int i=1;i<=n;i++){        LL k=x[i];        while (now<til&&getb(a[now+1],k)<getb(a[now],k)) now++;        f[i]=getb(a[now],k)+x[i]*s_p[i]-s_xp[i]+c[i];        jz x(s_p[i],s_xp[i]+f[i]);        while (til>1&&check(a[til]-a[til-1],x-a[til-1])<=0) til--;        now=min(now,til);a[++til]=x;    }    printf("%lld",f[n]);    return 0;}
原创粉丝点击