bzoj1096 [ZJOI2007]仓库建设

这道题是比较裸的斜率优化吧,维护两个前缀和一减就可以得出斜率方程。

然后就是模板类的题目了。

转一下hzw的吧

f[i]=min(f[j]+cal(j,i))

主要问题是如何在O1的时间内计算cal(j,i),即j+1到i这一段存入i所需的费用

我们可以利用前缀和的思想

sum[i]为p[i]的前缀和

如果所有物品都从0开始运到i,则费用为(sum[i]-sum[j])*x[i]

但由于物品的起始点不在0,所以每个物品可以少花费x[i]*p[i]

b[i]为x[i]*p[i]的前缀和

可得f[i]=min(f[j]+(sum[i]-sum[j])*x[i]-(b[i]-b[j])+c[i]

如果j>k且j比k更优

f[j]-f[k]+b[j]-b[k]<(sum[j]-sum[k])*x[i]

然后就解决了

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 using namespace std;
 7 
 8 typedef long long ll;
 9 const int NN=1e6+7;
10 
11 int n,l,r;
12 ll x[NN],p[NN],c[NN],q[NN];
13 ll f[NN],sum[NN],b[NN];
14 double get_left(int j,int k)
15 {
16     return (f[j]-f[k]+b[j]-b[k])*1.0/(double)(sum[j]-sum[k]);
17 }
18 int main()
19 {
20     //freopen("1.in","r",stdin);
21     //freopen("fzy.out","w",stdout);
22     scanf("%d",&n);
23     for (int i=1;i<=n;i++)
24     {
25         scanf("%d%d%d",&x[i],&p[i],&c[i]);
26         sum[i]=sum[i-1]+p[i];
27         b[i]=b[i-1]+p[i]*x[i];    
28     }
29     l=0;
30     q[r++]=0;
31     for (int i=1;i<=n;i++)
32     {
33         while(l+1<r&&(get_left(q[l+1],q[l])<=x[i])) l++;
34         int best=q[l];
35         f[i]=f[best]+(sum[i]-sum[best])*x[i]-(b[i]-b[best])+c[i];
36         while(r-2>=l&&get_left(q[r-1],q[r-2])>get_left(i,q[r-1])) r--;
37         q[r++]=i;    
38     }
39     printf("%lld",f[n]);
40 }

 

posted @ 2017-09-03 20:25  Kaiser-  阅读(252)  评论(0编辑  收藏  举报