BZOJP1096[ZJOI2007]仓库建设——solution

Description

  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公司寻找一个仓库建设的方案,使得总的费用(建造费用+运输费用)最小。 N ≤1000000。

      --by BZOJ
http://www.lydsy.com/JudgeOnline/problem.php?id=1096


首先明确一点,虽然原题是编号小的往编号大处运,但是出于习惯,本人将整个序列翻转,然后题目就变成从大往小运输了
(其实是因为博主一开始读错题了)
首先如果我们已经确定在哪些地方建仓库了,那么有就近运输的原则:
即一个工厂的物品向最近的仓库运输;
即确定了最后一个仓库,在此前面的仓库的数量和位置不影响之后的决策,应使其局部最优;
于是有如下方程:
//f[i]=f[j]+x[j+1]+sum1[i]-sum1[j]-len[j+1]*(s[i]-s[j]);

x[i]:在i建仓库的费用;

len[i]:i到1的距离;

s[i]:前i个工厂的物品和;

sum1[i]:把前i个工厂的物品运至1处的总费用,sum[i]=sum[i-1]+len[i]*(s[i]-s[i-1]);

(再次强调:本人将整个序列翻转,然后题目就变成从大往小运输了)

枚举最后一个仓库的位置为j+1,则前j个位置取最优值f[j],之后的花费是建仓库的x[j+1]和把之后的物品运到j+1位置的费用;

然后因为数据范围,所以需要斜率优化:

//f[i]=f[j]+x[j+1]+sum1[i]-sum1[j]-len[j+1]*(s[i]-s[j]);
//f[i]=-len[j+1]*s[i]+f[j]+x[j+1]-sum1[j]+len[j+1]*s[j]+sum1[i];
//f[i]=Y+sum1[i];
//Y=K*s[i]+B;
//K=-len[j+1];
//B=f[j]+x[j+1]-sum1[j]+len[j+1]*s[j];

维护上凸即可;

代码如下:

#include<cstdio>
#define ll long long 
using namespace std;
long long Y(int ,int );
long long K(int );
long long B(int );
int cmp(int ,int ,int );
int n;
int que[2000000];
long long f[1000010],x[1000010],sum1[1000010],len[1000010],s[1000010];
int main()
{
    int i,j,k,h=0,t=0;
    long long nu1;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%lld%lld%lld",&len[n-i+1],&s[n-i+1],&x[n-i+1]);
    }
    nu1=len[1];
    for(i=1;i<=n;i++){
        len[i]=nu1-len[i];
        sum1[i]=sum1[i-1]+s[i]*len[i];
        s[i]+=s[i-1];
    }
    for(i=1;i<=n;i++){
        while(h<t&&Y(i,que[h])>=Y(i,que[h+1]))h++;
        f[i]=(ll)Y(i,que[h])+sum1[i];
        while(h<t&&cmp(i,que[t],que[t-1]))
            t--;
        que[++t]=i;
    }
    printf("%lld",f[n]);
    return 0;
}
long long Y(int i,int j){
    long long k;
    k=K(j)*s[i]+B(j);
    return k;
}
long long K(int j){
    return -len[j+1];
}
long long B(int j){
    return f[j]+x[j+1]-sum1[j]+len[j+1]*s[j];
}
int cmp(int x1,int p,int x3){
    long long k1=K(x1),k2=K(p),k3=K(x3),b1=B(x1),b2=B(p),b3=B(x3);
    ll w1=(k1-k3)*(b2-b1);
    ll w2=(k1-k2)*(b3-b1);
    return w1<=w2;
}

 

posted @ 2017-04-21 09:24  F.W.Nietzsche  阅读(177)  评论(0编辑  收藏  举报