1096: [ZJOI2007]仓库建设

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公司寻找一个仓库建设的方案,使得总的费用(建造费用+运输费用)最小。

Input

  第一行包含一个整数N,表示工厂的个数。接下来N行每行包含两个整数Xi, Pi, Ci, 意义如题中所述。

Output

  仅包含一个整数,为可以找到最优方案的费用。

Sample Input

3
0 5 10
5 3 100
9 6 10

Sample Output

32

HINT

 

在工厂1和工厂3建立仓库,建立费用为10+10=20,运输费用为(9-5)*3 = 12,总费用32。如果仅在工厂3建立仓库,建立费用为10,运输费用为(9-0)*5+(9-5)*3=57,总费用67,不如前者优。

【数据规模】

对于100%的数据, N ≤1000000。 所有的Xi, Pi, Ci均在32位带符号整数以内,保证中间计算结果不超过64位带符号整数。 

 
 
这道题首先可以有一个基本思路,
f[i][j]表示i到j的最小花费,
f[i][j]=min(f[i][k]+k到j的花费)
这样是n^3考虑优化。。。
显然我们只需要用f[i]表示i到1的最小花费
f[i]=min(f[j]+i到j的花费)
这样就变成了n^2
还是不可以,这个时候我们思考一下如何计算i到j的花费
我们可以用sum表示1到i的货物数之和
如果直接乘距离的话会多算,所以我们b来表示第i个仓库到1的花费,
我们用(sum[i-1]-sum[j])*x[i]-(b[i-1]-b[j])+c[i]即可。。。
然后我们发现n^2还是不行,
我们再来看现在的状态转移方程:f[i]=min(f[j]+(sum[i-1]-sum[j])*x[i]-(b[i-1]-b[j])+c[i])
变形得到:(f[i]-f[j]+b[i-1]-b[j])/(sum[i-1]-sum[j])=x[i]  c[i]看做常数。。。
这样就变成了斜率优化。。。
若j比k更优
则 (f[j]-f[k]+b[j]-b[k])/(sum[j]-sum[k])<x[i]
所以就可做了。。。
 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<set>
12 #define inf 1000000000
13 #define maxn 1000000+5
14 #define maxm 10000+5
15 #define eps 1e-10
16 #define ll long long
17 #define for0(i,n) for(int i=0;i<=(n);i++)
18 #define for1(i,n) for(int i=1;i<=(n);i++)
19 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
20 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
22 using namespace std;
23 int n,q[maxn];
24 ll x[maxn],c[maxn],p[maxn],sum[maxn],b[maxn],f[maxn];
25 int read(){
26     int x=0,f=1;char ch=getchar();
27     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
28     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
29     return x*f;
30 }
31 double k(int j,int k){
32     return (double)(f[j]-f[k]+b[j]-b[k])/(double)(sum[j]-sum[k]);
33 }
34 int main(){
35     //freopen("input.txt","r",stdin);
36     //freopen("output.txt","w",stdout);
37     n=read();
38     for1(i,n){
39         x[i]=read();p[i]=read();c[i]=read();
40         sum[i]=sum[i-1]+p[i];
41         b[i]=b[i-1]+p[i]*x[i];
42     }
43     int l=0,r=0;
44     for1(i,n){
45         while(l<r&&k(q[l+1],q[l])<(double)x[i])l++;
46         int j=q[l];
47         f[i]=f[j]+(sum[i-1]-sum[j])*x[i]-(b[i-1]-b[j])+c[i];
48         while(l<r&&k(i,q[r])<k(q[r],q[r-1]))r--;
49         q[++r]=i;
50     }
51     printf("%lld",f[n]);
52     return 0;
53 }
View Code

 

posted @ 2016-05-28 09:02  HTWX  阅读(129)  评论(0编辑  收藏  举报