zoukankan      html  css  js  c++  java
  • 【bzoj1096】[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公司寻找一个仓库建设的方案,使得总的费用(建造费用+运输费用)最小。

    *输入:
      第一行包含一个整数N,表示工厂的个数。接下来N行每行包含两个整数Xi, Pi, Ci, 意义如题中所述。

    *输出:
      仅包含一个整数,为可以找到最优方案的费用。

    *样例输入:
    3
    0 5 10
    5 3 100
    9 6 10

    *样例输出:
    32

    *提示:
    在工厂1和工厂3建立仓库,建立费用为10+10=20,运输费用为(9-5)*3 = 12,总费用32。如果仅在工厂3建立仓库,建立费用为10,运输费用为(9-0)*5+(9-5)*3=57,总费用67,不如前者优。
    【数据规模】
    对于100%的数据, N ≤1000000。 所有的Xi, Pi, Ci均在32位带符号整数以内,保证中间计算结果不超过64位带符号整数。

    *题解:
    斜率优化。
    首先我们很容易地可以列出DP方程:
    fi=mini1j=1(fj+calc(j+1,i)+ci)
    calc(j,i) 表示区间[j,i] 内的所有货物全部运送到i节点所需要的代价,fi 表示第i号节点建成仓库所需要的最小代价。
    这里如果计算calc(j,i) 的值我是参考hzwer学长的题解的,丢链接跑。
    首先我们先假设所有的货物都从1号节点出发,计sumipi 的前缀和,那么区间内的货物从1号节点到i号节点的费用就是(sumisumj)xi 。然后每个节点的货物可以少运送的费用为xipi 。于是我们计bixipi 的前缀和。然后DP的转移方程就变成了:
    fi=mini1j=1(fj+(sumisumj)xi(bibj)+ci)
    将式子稍微转化即可变成我们熟悉的斜率优化的形式:
    fi=sumixi+cibi+mini1j=1(fj+bjsumjxi)
    比较斜率优化的式子yjkixj,此时,fj+bj 就是点的纵坐标 yjsumj 就是点横坐标 xjxi 就是斜率ki。又因为这题里面斜率ki 和横坐标xj 都是单调的,所以我们可以用单调队列来维护凸包,复杂度O(n)。

    *代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    
    #ifdef WIN32
        #define LL "%I64d"
    #else
        #define LL "%lld"
    #endif
    
    #ifdef CT
        #define debug(...) printf(__VA_ARGS__)
        #define setfile() 
    #else
        #define debug(...)
        #define filename ""
        #define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout)
    #endif
    
    #define R register
    #define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
    #define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
    #define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
    #define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
    #define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
    #define cabs(_x) ((_x) < 0 ? (- (_x)) : (_x))
    char B[1 << 15], *S = B, *T = B;
    inline int F()
    {
        R char ch; R int cnt = 0; R bool minus = 0;
        while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
        ch == '-' ? minus = 1 : cnt = ch - '0';
        while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
        return minus ? -cnt : cnt;
    }
    #define maxn 1000010
    int x[maxn], p[maxn], c[maxn], q[maxn];
    long long b[maxn], sum[maxn], f[maxn];
    #define x(_i) (sum[_i])
    #define y(_i) (f[_i] + b[_i])
    inline double slope(R int i, R int j)
    {
        return (double) (y(i) - y(j)) / (x(i) - x(j));
    }
    int main()
    {
    //  setfile();
        R int n = F();
        for (R int i = 1; i <= n; ++i)
        {
            x[i] = F();
            p[i] = F();
            c[i] = F();
            sum[i] = sum[i - 1] + p[i];
            b[i] = b[i - 1] + 1ll * p[i] * x[i];
        }
    /*
        memset(f, 63, sizeof (f)); f[0] = 0;
        for (R int i = 1; i <= n; ++i)
        {
            for (R int j = 0; j < i; ++j)
                cmin(f[i], f[j] + (sum[i - 1] - sum[j]) * x[i] - b[i - 1] + b[j] + c[i]);
        }
    */
        R int h = 1, t = 1;
        q[h] = 0;
        for (R int i = 1; i <= n; ++i)
        {
            while (h < t && slope(q[h], q[h + 1]) < x[i]) ++h;
            R int j = q[h];
            f[i] = f[j] + (sum[i] - sum[j]) * x[i] - b[i] + b[j] + c[i];
            while (h < t && slope(q[t - 1], i) < slope(q[t - 1], q[t])) --t;
            q[++t] = i;
        }
        printf("%lld
    ", f[n] );
        return 0;
    }
    /*
    3
    0 5 10
    5 3 100
    9 6 10
    */
  • 相关阅读:
    C#拾遗(一、基本类型)
    JS正则表达式的test()方法检查汉字
    从程序员到项目经理(一)
    程序员基本素质要求
    似乎比较快
    Qt常用类
    QT 获取窗口 大小 信息
    QT 获取屏幕尺寸的法子
    Qt中 QString 和int, char等的“相互”转换
    qt 读取xml文件
  • 原文地址:https://www.cnblogs.com/cocottt/p/6764984.html
Copyright © 2011-2022 走看看