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

    一看是三维,死得没有悬念,只能想办法优化。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 }
时间: 2024-10-21 10:13:20

bzoj 1096 仓库建设 -斜率优化的相关文章

BZOJ 1096 [ZJOI2007]仓库建设 斜率优化dp

1096: [ZJOI2007]仓库建设 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1096 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚. 由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用.突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场

BZOJ 1096 ZJOI2007 仓库建设 斜率优化

题目大意:给定n个厂房,在其中一些建仓库,一个点如果没有仓库就要把仓库运到右侧的仓库中,求最小花销 很简单的斜率优化--之前刷斜率优化的时候怎么居然把这道题漏了 令f[i]为在i点建厂使i之前的货物全部安置的最小花销 则有 公式编辑器就是爽啊~ 令sump[i]为p[i]的前缀和 令sumxp[i]为p[i]*x[i]的前缀和 化简有 f[j] + sumxp[j] = x[i]*sump[j] + sumxp[i] - x[i]*sump[i] - C[i] + f[i] 其中 X[j]=su

bzoj-1096 1096: [ZJOI2007]仓库建设(斜率优化dp)

题目链接: 1096: [ZJOI2007]仓库建设 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用.突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏.由于地形的不同,在不同工厂建立仓库的费用可能是不同的.第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库的费用是Ci.对

【BZOJ-1096】仓库建设 斜率优化DP

1096: [ZJOI2007]仓库建设 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3719  Solved: 1633[Submit][Status][Discuss] Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用.突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先

P2120 [ZJOI2007]仓库建设 斜率优化dp

好题,这题是我理解的第一道斜率优化dp,自然要写一发题解.首先我们要写出普通的表达式,然后先用前缀和优化.然后呢?我们观察发现,x[i]是递增,而我们发现的斜率也是需要是递增的,然后就维护一个单调递增就行了. 放一个证明题解. 设f[i]表示在i点建仓库的最小费用,易得方程:f[i]=min(f[j]+(x[i]-x[j+1])*p[j+1]+(x[i]-x[j+1])*p[j+2]...) =min(f[j]+c[i]+x[i]*(p[j+1..i])-(x[j+1]*p[j+1]+...+x

[Bzoj1096][ZJOI2007]仓库建设(斜率优化)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1096 一开始想了想费用流,然后被数据范围pass掉了,感觉dp更可行一些. 只想到一个O(n2)的做法,看到式子比较复杂,就感觉像是斜率优化. dp[i]表示前i个工厂所求的最小费用,则第i个工厂一定会建一个仓库.转移方程为$dp[i]=min(dp[j]+\sum_{k=j}^{i-1}p[k]*(x[i]-x[k]))+c[i]$. 将式子展开,用sump表示p数组的前缀和,sum

[BZOJ1096] [ZJOI2007] 仓库建设 (斜率优化dp)

Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用.突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏.由于地形的不同,在不同工厂建立仓库的费用可能是不同的.第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库的费用是Ci.对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏

[ZJOI2007]仓库建设(斜率优化)

L公司有N个工厂,由高到底分布在一座山上. 工厂1在山顶,工厂N在山脚. 由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用. 突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏. 由于地形的不同,在不同工厂建立仓库的费用可能是不同的.第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库的费用是Ci. 对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏,而由于L公司产品的对外

BZOJ 1096 ZJOI 2007 仓库建设 斜率优化DP

题目大意:山坡上有一些仓库,下雨了,要把所有仓库中的东西转移出来,每转移一单位的东西走一个单位长度需要花费1,在i处建立一个仓库需要花费cost[i],求最小的花费. 思路:和小P的牧场好像啊... 记录两个前缀和,sum[i] = Σsrc[i] _sum[i] = Σsrc[i] * pos[i], 然后DP方程:f[i] = f[j] + (sum[i] - sum[j]) * pos[i] - _sum[i] + _sum[j] + cost[i] 注意转换long long 数据有可能