首页 > 代码库 > bzoj 1096 仓库建设 -斜率优化

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

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

技术分享    一看是三维,死得没有悬念,只能想办法优化。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]作为横坐标。因为xi是单调递增的,所以删掉上凸点,维护一条斜率递增的折线。

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 }

bzoj 1096 仓库建设 -斜率优化