• 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;
    }
  • 相关阅读:
    关于三次握手与四次挥手你要知道这些
    seafile看不见repo报500错误的解决方法
    VMWare Workstation 配置docker多macvlan网络方法
    利用Python3的dpkt库进行ARP扫描
    关于LAMP配置Let’s Encrypt SSL证书
    OpenSSL生成CA证书及终端用户证书
    CentOS7.2安装Vim8和YouCompleteMe
    CentOS 7.2安装Jenkins自动构建Git项目
    CentOS 7.2 安装Gerrit 2.14.6
    CentOS7.2编译GCC7.3
  • 原文地址:https://www.cnblogs.com/nietzsche-oier/p/6741889.html
Copyright © 2020-2023  润新知