【bzoj1096】仓库建设——斜率优化dp

题目链接

我们用sum[i]表示前i个工厂的产品数之和,b[i]表示x[i]*p[i]的前缀和,因此第j+1~i个工厂的产品运到第i个工厂的代价就是

  (sum[i]-sum[j])*x[i]-(b[i]-b[j])+ci[i]

最后f[i]的状态转移方程即为:

  f[i]=f[j]+(sum[i]-sum[j])*xi[i]-(b[i]-b[j])+ci[i]

斜率式的推导过程就不写了,最后可以化成:

  (f[j]+b[j]-f[k]-b[k])/(sum[j]-sum[k])<xi[i]-ci[i](k<j<i)

//然而刚开始最后的那个加号写成乘号导致WA了两次,要注意队列的q[0]=0(不是1!!!),还是要细心吧。

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 typedef long long LL;
 5 const int maxn=1000010;
 6 using namespace std;
 7 LL xi[maxn],pi[maxn],ci[maxn],sum[maxn],b[maxn],f[maxn],q[maxn];
 8 inline LL read()
 9 {
10     LL anss=0,f=1;char c=getchar();
11     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
12     while(c>='0'&&c<='9'){anss=anss*10+c-48;c=getchar();}
13     return anss*f;
14 }
15 inline double cal(LL a,LL bb)
16 {
17     return 1.0*(f[a]+b[a]-f[bb]-b[bb])/(sum[a]-sum[bb]);
18 }
19 int main()
20 {
21     int n;
22     n=read();
23     sum[0]=0;b[0]=0;
24     for(int i=1;i<=n;i++){
25         xi[i]=read();pi[i]=read();ci[i]=read();
26         sum[i]=sum[i-1]+pi[i];
27         b[i]=b[i-1]+xi[i]*pi[i];
28     }
29     int h=0,t=1;q[0]=0;f[0]=0;
30     for(int i=1;i<=n;i++){
31         while(h<t-1&&cal(q[h],q[h+1])<xi[i])h++;
32         f[i]=f[q[h]]+(sum[i]-sum[q[h]])*xi[i]-(b[i]-b[q[h]])+ci[i];
33         while(h<t-1&&cal(q[t-2],q[t-1])>cal(q[t-1],i))t--;
34         q[t++]=i;
35     }
36     printf("%lld",f[n]);
37     return 0;
38 }
bzoj1096
原文地址:https://www.cnblogs.com/JKAI/p/7465176.html