[BZOJ1096] [ZJOI2007] 仓库建设 (斜率优化dp)
Posted CtrlCV
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1096] [ZJOI2007] 仓库建设 (斜率优化dp)相关的知识,希望对你有一定的参考价值。
Description
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
0 5 10
5 3 100
9 6 10
Sample Output
HINT
【数据规模】
对于100%的数据, N ≤1000000。 所有的Xi, Pi, Ci均在32位带符号整数以内,保证中间计算结果不超过64位带符号整数。
Source
Solution
设$f[i]$表示在第$i$个工厂建仓库时前$i$个工厂的最小花费,则:
$\\displaystyle f[i]=min\\left\\{f[j]+\\sum_{k=j+1}^{i}(c[i]-c[k])*p[k]\\right\\}+c[i]$
$\\displaystyle=min\\left\\{f[j]+c[i]*\\sum_{k=j+1}^{i}p[k]-\\sum_{k=j+1}^{i}c[k]*p[k]\\right\\}+c[i]$
令$\\displaystyle sump[i]=\\sum_{j=1}^i p[j]$,$\\displaystyle sumxp[i]=\\sum_{j=1}^i x[j]*p[j]$,则:
$\\displaystyle f[i]=min\\big\\{\\ f[j]+x[i]*(sump[i]-sump[j])-(sumxp[i]-sumxp[j])\\ \\big\\}+c[i]$
据说$f[i]$满足决策单调性,辣么这一步的证明跳过= =b
设$j<k$且$k$比$j$优,那么最后化成的斜率式是这样的:$\\displaystyle\\frac{(f[k]+sumxp[k])-(f[j]+sumxp[j])}{sump[k]-sump[j]}<c[i]$
维护下凸壳搞一搞就行了
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int x[1000005], p[1000005], c[1000005], q[1000005]; 5 ll sump[1000005], sumxp[1000005], f[1000005]; 6 7 double slope(int i) 8 { 9 return 1.0 * (f[q[i]] + sumxp[q[i]] - f[q[i - 1]] - sumxp[q[i - 1]]) / (sump[q[i]] - sump[q[i - 1]]); 10 } 11 12 int main() 13 { 14 int n, front = 0, back = 1; 15 scanf("%d", &n); 16 for(int i = 1; i <= n; ++i) 17 { 18 scanf("%d%d%d", x + i, p + i, c + i); 19 sump[i] = sump[i - 1] + p[i]; 20 sumxp[i] = sumxp[i - 1] + (ll)x[i] * p[i]; 21 } 22 for(int i = 1; i <= n; ++i) 23 { 24 while(front < back - 1 && slope(front + 2) < x[i]) 25 ++front; 26 int j = q[front + 1]; 27 f[i] = f[j] + x[i] * (sump[i] - sump[j]) - sumxp[i] + sumxp[j] + c[i]; 28 q[++back] = i; 29 while(front < back - 2 && slope(back) < slope(back - 1)) 30 q[--back] = i; 31 } 32 printf("%lld\\n", f[n]); 33 return 0; 34 }
以上是关于[BZOJ1096] [ZJOI2007] 仓库建设 (斜率优化dp)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ_1096_[ZJOI2007]_仓库建设_(斜率优化动态规划+单调队列+特殊的前缀和技巧)