BZOJ1096 [ZJOI2007]仓库建设

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

  

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

 

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

 
 
正解:DP+斜率优化
解题报告:
  上午校内自测考我的题目,我就可以在机房里面刷题,嘿嘿嘿。
  开始没看到只能往编号大的运输这个条件,结果一直没想出来朴素DP怎么写...
  朴素的式子就是:$${f[i]=min(f[j]+Xi*{sum_{k=j+1}^{i}P[k]} - sum_{k=j+1}^{i}Xk*Pk } )+ Ci$$
  这是n^2的做法,还是那句话,斜率优化的DP式子长得就是一副很可推的样子,不妨设$${Si=sum_{k=1}^{i}X[k]*P[k]}$$
  $${SPi=sum_{k=1}^{i}P[k]}$$
  那么式子变成了: $${f[i]=min(f[j]+Xi*(SPi-SPj)- (Si-Sj) )+ Ci}$$
  假设存在k<j,且j的决策比k优,即
   $${ (f[j]+Xi*(SPi-SPj)- (Si-Sj) )+ Ci  <  (f[k]+Xi*(SPi-SPk)- (Si-Sk) )+ Ci  }$$
  化简可知:$${f[j]-f[k]+Sj-Sk < Xi*(SPj-SPk) }$$
  把右边除过去,就会发现
  $${ frac{f[j]-f[k]+Sj-Sk}{SPj-SPk} < Xi }$$
  哇,这和昨天做的题目好像啊!这就是一个斜率式嘛
  单调队列维护斜率单增的下凸包,发现队首不满足上式了就pop掉,队尾不满足同样pop。
 
 1 //It is made by ljh2000
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 using namespace std;
14 typedef long long LL;
15 const int inf = (1<<30);
16 const int MAXN = 1000011;
17 int n,head,tail;
18 int X[MAXN],P[MAXN],C[MAXN],dui[MAXN];
19 LL f[MAXN],s[MAXN],sp[MAXN];
20 
21 inline int getint()
22 {
23     int w=0,q=0; char c=getchar();
24     while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 
25     while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w;
26 }
27 inline LL count(int x,int y){  return ( (f[x]-f[y])+(s[x]-s[y]) ) / (sp[x]-sp[y]) ; }
28 inline void work(){
29     n=getint(); for(int i=1;i<=n;i++) X[i]=getint(),P[i]=getint(),C[i]=getint(),s[i]=s[i-1]+(LL)X[i]*P[i],sp[i]=sp[i-1]+P[i];
30     dui[head=tail=1]=0; int from;
31     for(int i=1;i<=n;i++) {
32     while(head<tail && count(dui[head+1],dui[head])<X[i]) head++;
33     from=dui[head]; f[i]=(LL)f[from]+X[i]*(sp[i]-sp[from])-(s[i]-s[from])+C[i];
34     while(head<tail && count(dui[tail],dui[tail-1])>count(i,dui[tail])) tail--;
35     dui[++tail]=i;
36     }
37     printf("%lld",f[n]);
38 }
39 
40 int main()
41 {
42     work();
43     return 0;
44 }
原文地址:https://www.cnblogs.com/ljh2000-jump/p/6015002.html