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 }