1. 程式人生 > 其它 >倉庫建設

倉庫建設

題面

 

題目描述

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) 


#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;
}