BZOJ1096: [ZJOI2007]仓库建设

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

 


斜率优化
设f[i]表示第i个工厂建立仓库的前i个工厂得到解决的最小花费
则f[i]=min{f[k]+cost[k+1,i] | 0<=k<i } + C[i]
容易得出
cost[L,R]=P[L]+(x[R]-x[L])+P[L+1]*(x[R]-x[L+1])+……+P[R]*(x[R]-x[R])
=x[R]*(P[L~R])-(x[L]*P[L]+x[L+1]*P[L+1]+……+x[R]*P[R])
记sumP[i]=P[1~i]
sumPX[i]=x[1]*P[1]+x[2]*P[2]+……+x[i]*P[i]
则f[i]=min{f[k]+sumP[i]*x[i]-sumP[k]*x[i]-sumPX[i]+sumPX[k] | 0<=k<i } + C[i]
=min{f[k]-sumP[k]*x[i]+sumPX[k] | 0<=k<i } + sumP[i]*x[i]-sumPX[i]+C[i]
发现{}里面的是f[k]-sumP[k]*x[i]+sumPX[k],拿出来研究
1)证明决策单调性
设在状态i下 j<k k比j更优 则有:
f[k]-sumP[k]*x[i]+sumPX[k]<f[j]-sumP[j]*x[i]+sumPX[j]             (1)
则在状态t下(t>i)若有
f[k]-sumP[k]*x[t]+sumPX[k]<f[j]-sumP[j]*x[t]+sumPX[j]
(发现x[i]是关于i的增函数,t>i则x[t]>x[i],设x[t]=x[i]+v(v>0))
即f[k]-sumP[k]*(x[i]+v)+sumPX[k]<f[j]-sumP[j]*(x[i]+v)+sumPX[j]
即f[k]-sumP[k]*x[i]+sumPX[k]<f[j]-sumP[j]*[i]+sumPX[j] 且 -sumP[k]*v<-sumP[j]*v
由(1)及sumP[i]是增函数可知,命题成立
2)写出斜率方程
若f[k]-sumP[k]*x[i]+sumPX[k]<=[j]-sumP[j]*x[i]+sumPX[j]
则(f[k]-f[j]-sumPX[k]+sumPX[j])/(sumP[k]-sumP[j])<=x[i]

故当(f[k]-f[j]-sumPX[k]+sumPX[j])/(sumP[k]-sumP[j])<=x[i]时,若有j<k,那么k比j更优
由于是小于号,所以斜率越大,随着x[i]的增大,被选中的几乎更大,
所以l到r:     斜率 小——>大
优劣程度是:优劣 优——>劣

 

 1 /**************************************************************
 2     Problem: 1096
 3     User: white_hat_hacker
 4     Language: C++
 5     Result: Accepted
 6     Time:1980 ms
 7     Memory:51604 kb
 8 ****************************************************************/
 9  
10 #include<cstdio>
11 #include<cstdlib>
12 #include<algorithm>
13 #include<cstring>
14 #include<cmath>
15 #include<map>
16 #include<set>
17 #include<queue>
18 #include<vector>
19 #define INF 0x7f7f7f7f
20 #define pii pair<int,int>
21 #define ll long long
22 #define MAXN 1000005
23 using namespace std;
24 int read(){
25     int x=0,f=1;char ch=getchar();
26     while(ch<'0'||ch>'9'){if('-'==ch)f=-1;ch=getchar();}
27     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
28     return x*f;
29 }
30 int n;
31 ll x[MAXN],P[MAXN],C[MAXN];
32 ll sumP[MAXN],sumPX[MAXN];
33 int q[MAXN];
34 ll f[MAXN];
35 double slope(int k,int j){
36     return (f[k]-f[j]-sumPX[j]+sumPX[k])/(1.0*(sumP[k]-sumP[j]));
37 }
38  
39 int main()
40 {
41 //  freopen("data.in","r",stdin);
42     n=read();
43     for(int i=1;i<=n;i++){
44         x[i]=read();
45         P[i]=read();
46         C[i]=read();
47         sumP[i]=sumP[i-1]+P[i];
48         sumPX[i]=sumPX[i-1]+P[i]*x[i];
49     }
50     int l=1,r=0;
51     q[++r]=0;
52     for(int i=1;i<=n;i++){
53         while(l<r&&slope(q[l],q[l+1])<=(double)x[i]) l++;
54         int t=q[l];
55         f[i]=f[t]-sumP[t]*x[i]+sumPX[t]+sumP[i]*x[i]-sumPX[i]+C[i];
56         while(l<r&&slope(i,q[r])<slope(q[r-1],q[r])) r--;
57         q[++r]=i;
58     }
59     printf("%lld\n",f[n]);
60     return 0;
61 }

 

 

 
 
posted @ 2017-10-26 20:56  white_hat_hacker  阅读(74)  评论(0编辑  收藏