仓库建设

题面

 

题目描述

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 ,运输费用为 (95)×3=12,总费用 32

数据范围与约定

对于 20% 的数据,保证 n500。

对于 40% 的数据,保证 n104。

对于 100% 的数据,保证  1n1060xi,pi,ci<231

对于任意的 1i<n,保证 xi<xi+1

设答案为 ans,保证 ans+ (i=1)∑(n)  pixi<263

 



    f[i]:在i处修建仓库的最小费用 
    
则有: 
    f[i] = min{ f[j] + x[i] * sigma(p[l]) - sigma(x[l]*p[l]) } + c[i]
        (0<=j<i)               (j+1<=l<=i)   (j+1<=l<=i)

用前缀和优化,令sump[i]=sigma( p[i] ),sum[i]=sigma(x[i]*p[i]),则原始转化成: 
                         (1<=i<=i)           (1<=i<=i)
     f[i] = min{ f[j] + x[i] * (sump[i] - sump[j]) - (sum[i] - sum[j]) } + c[i]
     
若决策j优于决策k,则
  f[j] + x[i] * (sump[i] - sump[j]) - (sum[i] - sum[j])
< f[k] + x[i] * (sump[i] - sump[k]) - (sum[i] - sum[k])

两边一消化简
    (f[j] + sum[j]) - (f[k] + sum[k]) < x[i] * (sump[j] - sump[k])
即
        (f[j] + sum[j]) - (f[k] + sum[k])
        ---------------------------------   <  x[i]
                 sump[j] - sump[k]
                 
令 Y(x) = f[x] + sum[x] , X(x) = sump[x],则
                
                Y(j) - Y(k)
                -----------  <  x[i]
                X(j) - X(k) 
Code moo~~
#include<bits/stdc++.h>
#define Bessie moo~~
#define int long long
using namespace std;
const int N=10010006;
int n;
int x[N],p[N],c[N],sump[N],sum[N],f[N];
int q[N],t,h;
inline int Y(int a){return f[a]+sum[a];}
inline int X(int a){return sump[a];}
inline double slope(int j,int k){
    return 1.0*(Y(j)-Y(k))/(X(j)-X(k));
}
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>x[i]>>p[i]>>c[i];
        sump[i]=sump[i-1]+p[i];
        sum[i]=sum[i-1]+x[i]*p[i];
    }
    for(int i=1;i<=n;i++){
        while(h<t&&slope(q[h+1],q[h])<x[i])h++;//排除斜率小者
        int j=q[h];
        f[i]=f[j]+x[i]*(sump[i]-sump[j])-sum[i]+sum[j]+c[i];
        while(h<t&&slope(q[t],q[t-1])>slope(i,q[t]))t--;//加入的话斜率更小更能往下 
        q[++t]=i;
    }
    cout<<f[n];
    return 0;
}

 

posted @ 2022-03-18 11:11  Creator_157  阅读(190)  评论(0编辑  收藏  举报