斜率优化
设 f [ i ] f[i] f[i]为前 i i i个工厂且在 i i i建仓库的最小代价。那么有 f [ i ] = m i n { f [ j ] + c [ i ] + ∑ k = j i p [ k ] ∗ ( X [ i ] − X [ k ] ) } f[i]=min\{f[j]+c[i]+\sum_{k=j}^ip[k]*(X[i]-X[k])\} f[i]=min{f[j]+c[i]+∑k=jip[k]∗(X[i]−X[k])}。因为第 n n n个工厂一定要建仓库,那么答案就是 f [ n ] f[n] f[n]。
记 s 1 [ i ] = ∑ p [ i ] , s 2 [ i ] = ∑ X [ i ] ∗ p [ i ] s1[i]=\sum p[i],s2[i]=\sum X[i]*p[i] s1[i]=∑p[i],s2[i]=∑X[i]∗p[i]。那么 f [ i ] = m i n { f [ j ] + c [ i ] + ( s 1 [ i ] − s 1 [ j ] ) X [ i ] − s 2 [ i ] + s 2 [ j ] } f[i]=min\{f[j]+c[i]+(s1[i]-s1[j])X[i]-s2[i]+s2[j]\} f[i]=min{f[j]+c[i]+(s1[i]−s1[j])X[i]−s2[i]+s2[j]}。这是 n 2 n^2 n2的,考虑斜率优化。
设
x
<
y
x<y
x<y且
x
x
x优于
y
y
y:
f
[
x
]
+
c
[
i
]
+
(
s
1
[
i
]
−
s
1
[
x
]
)
X
[
i
]
−
(
s
2
[
i
]
−
s
2
[
x
]
)
<
f
[
y
]
+
c
[
i
]
+
(
s
1
[
i
]
−
s
1
[
y
]
)
X
[
i
]
−
(
s
2
[
i
]
−
s
2
[
y
]
)
f
[
x
]
−
f
[
y
]
+
s
2
[
x
]
−
s
2
[
y
]
<
(
s
1
[
x
]
−
s
1
[
y
]
)
X
[
i
]
f
[
x
]
−
f
[
y
]
+
s
2
[
x
]
−
s
2
[
y
]
s
1
[
x
]
−
s
1
[
y
]
<
X
[
i
]
\begin{aligned} f[x]+c[i]+(s1[i]-s1[x])X[i]-(s2[i]-s2[x])&<f[y]+c[i]+(s1[i]-s1[y])X[i]-(s2[i]-s2[y])\\ f[x]-f[y]+s2[x]-s2[y]&<(s1[x]-s1[y])X[i]\\ \frac{f[x]-f[y]+s2[x]-s2[y]}{s1[x]-s1[y]}&<X[i] \end{aligned}
f[x]+c[i]+(s1[i]−s1[x])X[i]−(s2[i]−s2[x])f[x]−f[y]+s2[x]−s2[y]s1[x]−s1[y]f[x]−f[y]+s2[x]−s2[y]<f[y]+c[i]+(s1[i]−s1[y])X[i]−(s2[i]−s2[y])<(s1[x]−s1[y])X[i]<X[i]
代码:
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1000005
#define F inline
using namespace std;
typedef long long LL;
int n,X[N],c[N],p[N],q[N];
LL f[N],s1[N],s2[N];
F char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
return l==r?EOF:*l++;
}
F int _read(){
int x=0,f=1; char ch=readc();
while (!isdigit(ch)){ if (ch=='-') f=-1; ch=readc(); }
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
return x*f;
}
#define calc(x,y) (1.0*(f[x]-f[y]+s2[x]-s2[y])/(s1[x]-s1[y]))
int main(){
n=_read(); int l=0,r=0;
for (int i=1;i<=n;i++){
X[i]=_read(),p[i]=_read(),c[i]=_read();
s1[i]=s1[i-1]+p[i],s2[i]=s2[i-1]+1ll*p[i]*X[i];
}
for (int i=1;i<=n;q[++r]=i,i++){
while (l<r&&calc(q[l],q[l+1])<X[i]) l++;
f[i]=f[q[l]]+c[i]+(s1[i]-s1[q[l]])*X[i]-s2[i]+s2[q[l]];
while (l<r&&calc(q[r-1],q[r])>calc(q[r],i)) r--;
}
return printf("%lld\n",f[n]),0;
}