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的方程(公式编辑器坏了,只能用画图了,请谅解)

$f\left [ i \right ] = \min\left \{ f\left [ j \right ] + \sum_{k = j + 1}^{i - 1}\left ( x_{i} - x_{k} \right )p_{k} \right \} + 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"\n", f[n]);
108 }
109 
110 int main() {
111     init();
112     solve();
113     return 0;
114 }
posted @ 2017-01-29 22:20  阿波罗2003  阅读(267)  评论(0编辑  收藏  举报