[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

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位带符号整数。 

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 }
View Code

 

以上是关于[BZOJ1096] [ZJOI2007] 仓库建设 (斜率优化dp)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1096ZJOI2007仓库建设

[bzoj 1096] [ZJOI2007]仓库建设

BZOJ_1096_[ZJOI2007]_仓库建设_(斜率优化动态规划+单调队列+特殊的前缀和技巧)

BZOJ1096-[ZJOI2007]仓库建设

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

bzoj1096: [ZJOI2007]仓库建设