zoukankan      html  css  js  c++  java
  • bzoj 1096 仓库建设 -斜率优化

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

    Input

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

    Output

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

    Sample Input

    3
    0 5 10
    5 3 100
    9 6 10

    Sample Output

    32

    Hint

      在工厂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方程推错了两次(每次都是从n往前),于是无限WA...第三次终于推对了。。(说完一堆废话赶快写正解)

      朴素dp的方程(公式编辑器坏了,只能用画图了,请谅解)

    $fleft [ i ight ] = minleft { fleft [ j ight ] + sum_{k = j + 1}^{i - 1}left ( x_{i} - x_{k} ight )p_{k} ight } + c_{i}$

      一看是三维,死得没有悬念,只能想办法优化。Sigma一在更不好优化,只能先展开

        发现P的求和和xP的求和都是可以用前缀和搞定的,于是设,sump[i] = P1 + P2 + ... + Pi,sumxp[i] = x1P1 + x2P2 + ... + xiPi

        于是方程变成        f[i] = min{f[j] + xi(sump[i - 1] - sump[j]) - sumxp[i - 1] + sump[j]} + Ci

        现在假设能转移到状态i的有两个状态j, k(j < k),如果j比k优,那么

    f[j] + xi(sump[i - 1] - sump[j]) - sumxp[i - 1] + sump[j] < f[k] + xi(sump[i - 1] - sump[k]) - sumxp[i - 1] + sump[k]

        拆括号化简

    f[j] - xisump[j] + sump[j] < f[k] - xisump[k] + sump[k]

        右边保留和i有关的单项式

    (f[j] + sump[j]) - (f[k] + sump[k]) < xi(sump[j] - sump[k])

        移项(还是注意不等号的方向)

        于是又愉快地得到了斜率方程,对于状态i,(f[i] + sump[i])作为纵坐标,sump[i]作为横坐标,删掉上凸点,维护一条斜率递增的折线。

    Code

      1 /**
      2  * bzoj
      3  * Problem#1096
      4  * Accepted
      5  * Time:2312ms
      6  * Memory:36464k
      7  */
      8 #include<iostream>
      9 #include<sstream>
     10 #include<cstdio>
     11 #include<cmath>
     12 #include<cstdlib>
     13 #include<cstring>
     14 #include<cctype>
     15 #include<queue>
     16 #include<set>
     17 #include<map>
     18 #include<stack>
     19 #include<vector>
     20 #include<algorithm>
     21 #ifdef    WIN32
     22 #define    AUTO "%I64d"
     23 #else
     24 #define AUTO "%lld"
     25 #endif
     26 using namespace std;
     27 typedef bool boolean;
     28 #define smin(a, b) (a) = min((a), (b))
     29 #define smax(a, b) (a) = max((a), (b))
     30 template<typename T>
     31 inline void readInteger(T& u){
     32     char x;
     33     int aFlag = 1;
     34     while(!isdigit((x = getchar())) && x != '-');
     35     if(x == '-'){
     36         aFlag = -1;
     37         x = getchar();
     38     }
     39     for(u = x - '0'; isdigit((x = getchar())); u = u * 10 + x - '0');
     40     ungetc(x, stdin);
     41     u *= aFlag;
     42 }
     43 
     44 template<typename T>
     45 class IndexedDeque{
     46     public:
     47         T* list;
     48         int pfront;
     49         int prear;
     50         IndexedDeque():list(NULL), pfront(0), prear(0){        }
     51         IndexedDeque(int size):pfront(0), prear(0){
     52             list = new T[size];
     53         }
     54         void push_front(T x){    list[--pfront] = x;        }
     55         void push_back(T x)    {    list[prear++] = x;        }
     56         void pop_front()    {    ++pfront;                }
     57         void pop_back()        {    --prear;                }
     58         T     front()        {    return list[pfront];    }
     59         T     rear()            {    return list[prear - 1];        }
     60         T& operator [](int pos){            return list[pfront + pos];        }
     61         int size()            {    return prear - pfront;    }
     62 };
     63 
     64 template<typename T>
     65 inline void aalloc(T*& array, int size){    array = new T[(const int)(size + 1)];    }
     66 
     67 int n;
     68 long long* sump;
     69 long long* sumxp;
     70 int* c;
     71 int* x;
     72 long long* f;
     73 IndexedDeque<int> que;
     74 
     75 long long y_pos(int i)    {    return f[i] + sumxp[i];    }
     76 double slope(int j, int k)    {    return (y_pos(j) - y_pos(k)) * 1.0 / (sump[j] - sump[k]);    }
     77 double cmpSlope(int i, int j, int k) {    return slope(j, k) - x[i];    }    
     78 
     79 inline void init() {
     80     readInteger(n);
     81     aalloc(sump, n);
     82     aalloc(sumxp, n);
     83     aalloc(c, n);
     84     aalloc(x, n);
     85     aalloc(f, n + 1);
     86     sump[0] = sumxp[0] = x[0] = 0;
     87     for(int i = 1, p; i <= n; i++){
     88         readInteger(x[i]);
     89         readInteger(p);
     90         readInteger(c[i]);
     91         sump[i] = sump[i - 1] + p;
     92         sumxp[i] = sumxp[i - 1] + x[i] * 1LL * p;
     93     }
     94 }
     95 
     96 inline void solve() {
     97     que = IndexedDeque<int>(n + 5);
     98     f[0] = 0;
     99     que.push_back(0);
    100     for(int i = 1; i <= n; i++) {
    101         while(que.size() > 1 && cmpSlope(i, que[0], que[1]) < 0)    que.pop_front();
    102         int j = que.front();
    103         f[i] = f[j] + x[i] * (sump[i - 1] - sump[j]) - sumxp[i - 1] + sumxp[j] + c[i];
    104         while(que.size() > 1 && slope(que[que.size() - 2], que[que.size() - 1]) >= slope(que[que.size() - 1], i))    que.pop_back();
    105         que.push_back(i);
    106     }
    107     printf(AUTO"
    ", f[n]);
    108 }
    109 
    110 int main() {
    111     init();
    112     solve();
    113     return 0;
    114 }
  • 相关阅读:
    2012个人总结与展望
    C++Event机制的简单实现
    string与char*比较 ——why use string
    创建型模式学习总结——设计模式学习笔记
    Bridge模式——设计模式学习笔记
    Singleton模式——设计模式学习
    Adapter模式——设计模式学习笔记
    C++ 申请连续的对象内存
    7 个致命的 Linux 命令与个人评论
    关于保存Activity的状态
  • 原文地址:https://www.cnblogs.com/yyf0309/p/6357763.html
Copyright © 2011-2022 走看看