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公司寻找一个仓库建设的方案,使得总的费用(建造费用+运输费用)最小。 N ≤1000000。
--by BZOJ
http://www.lydsy.com/JudgeOnline/problem.php?id=1096
首先明确一点,虽然原题是编号小的往编号大处运,但是出于习惯,本人将整个序列翻转,然后题目就变成从大往小运输了
(其实是因为博主一开始读错题了)
首先如果我们已经确定在哪些地方建仓库了,那么有就近运输的原则:
即一个工厂的物品向最近的仓库运输;
即确定了最后一个仓库,在此前面的仓库的数量和位置不影响之后的决策,应使其局部最优;
于是有如下方程:
//f[i]=f[j]+x[j+1]+sum1[i]-sum1[j]-len[j+1]*(s[i]-s[j]);
x[i]:在i建仓库的费用;
len[i]:i到1的距离;
s[i]:前i个工厂的物品和;
sum1[i]:把前i个工厂的物品运至1处的总费用,sum[i]=sum[i-1]+len[i]*(s[i]-s[i-1]);
(再次强调:本人将整个序列翻转,然后题目就变成从大往小运输了)
枚举最后一个仓库的位置为j+1,则前j个位置取最优值f[j],之后的花费是建仓库的x[j+1]和把之后的物品运到j+1位置的费用;
然后因为数据范围,所以需要斜率优化:
//f[i]=f[j]+x[j+1]+sum1[i]-sum1[j]-len[j+1]*(s[i]-s[j]); //f[i]=-len[j+1]*s[i]+f[j]+x[j+1]-sum1[j]+len[j+1]*s[j]+sum1[i]; //f[i]=Y+sum1[i]; //Y=K*s[i]+B; //K=-len[j+1]; //B=f[j]+x[j+1]-sum1[j]+len[j+1]*s[j];
维护上凸即可;
代码如下:
#include<cstdio> #define ll long long using namespace std; long long Y(int ,int ); long long K(int ); long long B(int ); int cmp(int ,int ,int ); int n; int que[2000000]; long long f[1000010],x[1000010],sum1[1000010],len[1000010],s[1000010]; int main() { int i,j,k,h=0,t=0; long long nu1; scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%lld%lld%lld",&len[n-i+1],&s[n-i+1],&x[n-i+1]); } nu1=len[1]; for(i=1;i<=n;i++){ len[i]=nu1-len[i]; sum1[i]=sum1[i-1]+s[i]*len[i]; s[i]+=s[i-1]; } for(i=1;i<=n;i++){ while(h<t&&Y(i,que[h])>=Y(i,que[h+1]))h++; f[i]=(ll)Y(i,que[h])+sum1[i]; while(h<t&&cmp(i,que[t],que[t-1])) t--; que[++t]=i; } printf("%lld",f[n]); return 0; } long long Y(int i,int j){ long long k; k=K(j)*s[i]+B(j); return k; } long long K(int j){ return -len[j+1]; } long long B(int j){ return f[j]+x[j+1]-sum1[j]+len[j+1]*s[j]; } int cmp(int x1,int p,int x3){ long long k1=K(x1),k2=K(p),k3=K(x3),b1=B(x1),b2=B(p),b3=B(x3); ll w1=(k1-k3)*(b2-b1); ll w2=(k1-k2)*(b3-b1); return w1<=w2; }