Problem
【ZJOI2007】仓库建设
TimeLimit:10Sec
MemoryLimit:162MB
Description
L公司有N个工厂,由高到底分布在一座山上。如图所示,工厂1在山顶,工厂N在山脚。由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在露天,以节省费用。突然有一天,L公司的总裁L先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是L先生决定紧急在某些工厂建立一些仓库以免产品被淋坏。由于地形的不同,在不同工厂建立仓库的费用可能是不同的。第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库的费用是Ci。对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏,而由于L公司产品的对外销售处设置在山脚的工厂N,故产品只能往山下运(即只能运往编号更大的工厂的仓库),当然运送产品也是需要费用的,假设一件产品运送1个单位距离的费用是1。假设建立的仓库容量都都是足够大的,可以容下所有的产品。你将得到以下数据:
- 工厂i距离工厂1的距离Xi(其中X1=0)
- 工厂i目前已有成品数量Pi
- 在工厂i建立仓库的费用Ci
请你帮助L公司寻找一个仓库建设的方案,使得总的费用(建造费用+运输费用)最小。
第一行包含一个整数N,表示工厂的个数。接下来N行每行包含两个整数Xi,Pi,Ci, 意义如题中所述。
Output
仅包含一个整数,为可以找到最优方案的费用。
Sample Output
标签:斜率优化DP
Solution
由题意,易得到DP方程:f[i]=c[i]+minj=0i−1{f[j]+∑k=j+1ip[k]×(x[i]−x[k])}
那么对于当前DP到的位置i,一定存在p,q∈[0,i)使得
f[p]+k=p+1∑ip[k]×(x[i]−x[k])f[p]+k=p+1∑ip[k]×x[i]−k=p+1∑ip[k]×x[k]Lets1[i]=j=1∑ip[j]×x[j]f[p]+(s2[i]−s2[p])×x[i]−s1[i]+s1[p]f[p]−s2[p]×x[i]+s1[p]s2[p]−s2[q](f[p]−f[q])+(s1[p]−s1[q])≤f[q]+k=q+1∑ip[k]×(x[i]−x[k])≤f[q]+k=q+1∑ip[k]×x[i]−k=q+1∑ip[k]×x[k],s2[i]=j=1∑ip[j]≤f[q]+(s2[i]−s2[q])×x[i]−s1[i]+s1[q]≤f[q]−s2[q]×x[i]+s1[q]≤x[i]
∴k(p,q)=s2[p]−s2[q](f[p]−f[q])+(s1[p]−s1[q])≤x[i]⟺pisbetterthanq
按照此斜率维护单调栈即可。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <bits/stdc++.h> #define MAX_N 1000000 using namespace std; typedef double dnt; typedef long long lnt; template <class T> inline void read(T &x) { x = 0; int c = getchar(), f = 1; for (; !isdigit(c); c = getchar()) if (c == 45) f = -1; for (; isdigit(c); c = getchar()) (x *= 10) += f*(c-'0'); } int n, c[MAX_N+5], x[MAX_N+5], m[MAX_N+5]; lnt s1[MAX_N+5], s2[MAX_N+5], f[MAX_N+5]; int l, r, sta[MAX_N+5]; dnt calc(int p, int q) {return (dnt)(f[p]-f[q]+s1[p]-s1[q])/(dnt)(s2[p]-s2[q]);} int main() { read(n); for (int i = 1; i <= n; i++) read(x[i]), read(m[i]), read(c[i]); for (int i = 1; i <= n; i++) s1[i] = s1[i-1]+1LL*m[i]*x[i], s2[i] = s2[i-1]+m[i]; for (int i = 1; i <= n; i++) { while (l < r && calc(sta[l+1], sta[l]) <= x[i]) l++; f[i] = f[sta[l]]+1LL*x[i]*(s2[i]-s2[sta[l]])-s1[i]+s1[sta[l]]+c[i]; while (l < r && calc(sta[r], sta[r-1]) > calc(i, sta[r])) r--; sta[++r] = i; } return printf("%lld", f[n]), 0; }
|