P2120 [ZJOI2007] 仓库建设题解
题目描述
L 公司有 n 个工厂,由高到低分布在一座山上,工厂 1 在山顶,工厂 n 在山脚。
由于这座山处于高原内陆地区(干燥少雨),L 公司一般把产品直接堆放在露天,以节省费用。突然有一天,L 公司的总裁 L 先生接到气象部门的电话,被告知三天之后将有一场暴雨,于是 L 先生决定紧急在某些工厂建立一些仓库以免产品被淋坏。
由于地形的不同,在不同工厂建立仓库的费用可能是不同的。第 i 个工厂目前已有成品 pi 件,在第 i 个工厂位置建立仓库的费用是 ci。
对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏,而由于 L 公司产品的对外销售处设置在山脚的工厂 n,故产品只能往山下运(即只能运往编号更大的工厂的仓库),当然运送产品也是需要费用的,一件产品运送一个单位距离的费用是 1。
假设建立的仓库容量都都是足够大的,可以容下所有的产品。你将得到以下数据:
- 工厂 i 距离工厂 1 的距离 xi(其中 x1=0)。
- 工厂 i 目前已有成品数量 pi。
- 在工厂 i 建立仓库的费用 ci。
请你帮助 L 公司寻找一个仓库建设的方案,使得总的费用(建造费用 + 运输费用)最小。
输入格式
输入的第一行是一个整数 n,代表工厂的个数。
第 2 到 (n+1) 行,每行有三个用空格隔开的整数,第 (i+1) 行的整数依次代表 xi, pi, ci。
输出格式
仅输出一行一个整数,代表最优方案的费用。
输入输出样例
输入 #1复制
3 0 5 10 5 3 100 9 6 10
输出 #1复制
32
说明/提示
样例输入输出 1 解释
在工厂 1 和工厂 3 建立仓库,建立费用为 10+10=20 ,运输费用为 (9−5)×3=12,总费用 32。
数据范围与约定
对于 20% 的数据,保证 n≤500。
对于 40% 的数据,保证 n≤104。
对于 100% 的数据,保证 1≤n≤106,0≤xi,pi,ci<231。
对于任意的 1≤i<n,保证 xi<xi+1。
设答案为 ans,保证 ans+i=1∑npixi<263。
思路
1024程序员节第一篇题解。
首先,可以发现,设fi为选第i个建仓库且前i个均安排好的数量,则答案为fq,q为其后所有产品数都为0的最小仓库编号。
可得:
其中
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,f[1000006],b[1000006],c[1000006],as=1e18+7,op=0;
struct one{
long long x,p,c;
}a[1000006];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].p>>a[i].c;
}
for(int i=1;i<=n;i++){
b[i]=b[i-1]+a[i].p;
}
for(int i=1;i<=n;i++){
c[i]=c[i-1]+b[i-1]*(a[i].x-a[i-1].x);
}
memset(f,63,sizeof(f));
f[0]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=i-1;j++){
f[i]=min(f[i],f[j]+c[i]-c[j]-b[j]*(a[i].x-a[j].x)+a[i].c);
}
}
for(int i=n;i>=1;i--){
if(op==0){
as=min(as,f[i]);
}
op+=a[i].c;
}
cout<<as<<endl;
return 0;
}
于是,设:
则:
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,f[1000006],b[1000006],c[1000006],as=1e18+7,op=0;
struct one{
long long x,p,c;
}a[1000006];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].p>>a[i].c;
}
for(int i=1;i<=n;i++){
b[i]=b[i-1]+a[i].p;
}
for(int i=1;i<=n;i++){
c[i]=c[i-1]+b[i-1]*(a[i].x-a[i-1].x);
}
memset(f,63,sizeof(f));
f[0]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=i-1;j++){
f[i]=min(f[i],f[j]-b[j]*a[i].x);
}
f[i]=f[i]+a[i].c+c[i];
f[i]=f[i]-c[i]+b[i]*a[i].x;
}
for(int i=n;i>=1;i--){
if(op==0){
as=min(as,f[i]+c[i]-b[i]*a[i].x);
}
op+=a[i].p;
}
cout<<as<<endl;
return 0;
}
若:
所以,维护凸包,用斜率优化DP即可。
#include<bits/stdc++.h>
using namespace std;
long long n,f[1000006],b[1000006],c[1000006],as=1e18+7,op=0,dl[1000006],ld=1,rd=1;
struct one{
long long x,p,c;
}a[1000006];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].p>>a[i].c;
}
for(int i=1;i<=n;i++){
b[i]=b[i-1]+a[i].p;
}
for(int i=1;i<=n;i++){
c[i]=c[i-1]+b[i-1]*(a[i].x-a[i-1].x);
}
memset(f,63,sizeof(f));
f[0]=0;
for(int i=1;i<=n;i++){
long long l=ld,r=rd-1,md=rd;
if(rd-ld+1>=2){
while(l<=r){
long long mid=(l+r)/2;
if((f[dl[mid+1]]-f[dl[mid]])>=a[i].x*(b[dl[mid+1]]-b[dl[mid]])){
md=min(md,mid);
f[i]=min(f[i],f[dl[mid]]-b[dl[mid]]*a[i].x);
f[i]=min(f[i],f[dl[mid+1]]-b[dl[mid+1]]*a[i].x);
r=mid-1;
}
else{
l=mid+1;
}
}
}
f[i]=min(f[i],f[dl[md]]-b[dl[md]]*a[i].x);
if(rd-ld<=100) for(int j=ld;j<=rd;j++){
f[i]=min(f[i],f[dl[j]]-b[dl[j]]*a[i].x);
}
f[i]=f[i]+a[i].c+c[i];
f[i]=f[i]-c[i]+b[i]*a[i].x;
while(rd-ld+1>=2&&(f[i]-f[dl[rd]])*(b[dl[rd]]-b[dl[rd-1]])<(f[dl[rd]]-f[dl[rd-1]])*(b[i]-b[dl[rd]])){
rd--;
//return 0;
}
//cout<<f[i]<<" "<<b[i]<<endl;
dl[++rd]=i;
}
for(int i=n;i>=1;i--){
if(op==0){
as=min(as,f[i]+c[i]-b[i]*a[i].x);
}
op+=a[i].p;
}
cout<<as<<endl;
return 0;
}

浙公网安备 33010602011771号