Problem
先有一些工厂,每个工厂有一些成品。先要在其中一些工厂的位置建立仓库,建立仓库会有一定的费用。每个没设立仓库的地方将成品运送至下面的仓库,费用为成品数乘距离。山脚一定有一个仓库。问最少需要的花费是多少
工厂
i
i
i 距离工厂
1
1
1 的距离
x
i
x_i
xi(其中
x
1
=
0
x_1=0
x1=0);
工厂
i
i
i 目前已有成品数量
p
i
p_i
pi;
在工厂
i
i
i 建立仓库的费用
c
i
c_i
ci。
Solution
设
f
[
i
]
f[i]
f[i] 表示在
i
i
i 处设立仓库的最小值。
i
i
i 前一点
j
j
j ,
j
j
j 向
i
i
i 运输需要花费
w
=
p
[
j
]
∗
(
x
[
i
]
−
x
[
j
]
)
=
p
[
j
]
∗
x
[
i
]
−
p
[
j
]
∗
x
[
j
]
w=p[j]*(x[i]-x[j])=p[j]*x[i]-p[j]*x[j]
w=p[j]∗(x[i]−x[j])=p[j]∗x[i]−p[j]∗x[j]
f [ i ] = m i n ( f [ j ] + x [ i ] ⋅ ∑ k = j + 1 i p [ k ] − ∑ k = j + 1 i ( x [ k ] ⋅ p [ k ] ) ) + c [ i ] f[i]=min(f[j]+x[i]\cdot\sum\limits_{k=j+1}^{i}p[k]-\sum\limits_{k=j+1}^{i}(x[k]\cdot p[k]))+c[i] f[i]=min(f[j]+x[i]⋅k=j+1∑ip[k]−k=j+1∑i(x[k]⋅p[k]))+c[i]
我们分别维护 p [ i ] p[i] p[i] 、 x [ i ] ⋅ p [ i ] x[i]\cdot p[i] x[i]⋅p[i] 前缀和,记作 s u m 1 、 s u m 2 sum1、sum2 sum1、sum2
则 f [ i ] = m i n ( f [ j ] + x [ i ] ⋅ ( s u m 1 [ i ] − s u m 1 [ j ] ) − ( s u m 2 [ i ] − s u m 2 [ j ] ) ) + c i f[i]=min(f[j]+x[i]\cdot(sum1[i]-sum1[j])-(sum2[i]-sum2[j]))+c_i f[i]=min(f[j]+x[i]⋅(sum1[i]−sum1[j])−(sum2[i]−sum2[j]))+ci
f [ j ] + s u m 2 [ j ] = f [ i ] − x [ i ] ⋅ ( s u m 1 [ i ] − s u m 1 [ j ] ) + s u m 2 [ i ] − c i f[j]+sum2[j]=f[i]-x[i]\cdot(sum1[i]-sum1[j])+sum2[i]-c_i f[j]+sum2[j]=f[i]−x[i]⋅(sum1[i]−sum1[j])+sum2[i]−ci
f [ j ] + s u m 2 [ j ] = x [ i ] ⋅ s u m 1 [ j ] + f [ i ] − x [ i ] ⋅ s u m 1 [ i ] + s u m 2 [ i ] − c i f[j]+sum2[j]=x[i]\cdot sum1[j]+f[i]-x[i]\cdot sum1[i]+sum2[i]-c_i f[j]+sum2[j]=x[i]⋅sum1[j]+f[i]−x[i]⋅sum1[i]+sum2[i]−ci
因此维护 ( s u m 1 [ j ] , f [ j ] + s u m 2 [ j ] ) (sum1[j],f[j]+sum2[j]) (sum1[j],f[j]+sum2[j])
Code
#include <cstdio>
#define ll long long
#define db double
#define N 1000010
int n,q[N];
ll sum1[N],sum2[N],f[N],x[N],p[N],c[N];
inline db X(int i){return sum1[i];}
inline db Y(int i){return f[i]+sum2[i];}
inline db slope(int i,int j){return (Y(j)-Y(i))/(X(j)-X(i));}
int main(){
freopen("a.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld%lld%lld",&x[i],&p[i],&c[i]);
sum1[i]=sum1[i-1]+p[i],sum2[i]=sum2[i-1]+p[i]*x[i];
}
int h=1,t=1;
for(int i=1;i<=n;i++){
while(h<t && slope(q[h],q[h+1])<x[i]) h++;
f[i]=f[q[h]]+x[i]*(sum1[i]-sum1[q[h]])-(sum2[i]-sum2[q[h]])+c[i];
while(h<t && slope(q[t],q[t-1])>slope(q[t],i)) t--;
q[++t]=i;
}
printf("%lld\n",f[n]);
return 0;
}