[Bzoj1096][ZJOI2007]仓库建设(斜率优化)

Posted sainsist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Bzoj1096][ZJOI2007]仓库建设(斜率优化)相关的知识,希望对你有一定的参考价值。

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1096

一开始想了想费用流,然后被数据范围pass掉了,感觉dp更可行一些。

只想到一个O(n2)的做法,看到式子比较复杂,就感觉像是斜率优化。

dp[i]表示前i个工厂所求的最小费用,则第i个工厂一定会建一个仓库。转移方程为$dp[i]=min(dp[j]+\sum_k=j^i-1p[k]*(x[i]-x[k]))+c[i]$。

将式子展开,用sump表示p数组的前缀和,sumpx表示p数组*x数组的前缀和。

方程就变成了$dp[i]=min(dp[j] + c[i] + (sumx[i - 1] - sumx[j])*x[i] - (sumpx[i - 1] - sumpx[j]))$

然后设k<j<i时,存在从j转移到i比从k转移到i更优。

则$dp[j] + c[i] + (sumx[i - 1] - sumx[j])*x[i] - (sumpx[i - 1] - sumpx[j])<dp[k] + c[i] + (sumx[i - 1] - sumx[k])*x[i] - (sumpx[i - 1] - sumpx[k])$

移项展开可以得到$dp[j] + sumpx[j] - (dp[k] + sumpd[k]) < (sump[j] - sump[k])*x[i]$

设$f[i]=dp[i]+sumpx[i]$,$T[i]=sump[i]$。

则上式变成$(f[j]-f[k])/(T[j]-T[k])<x[i]$。这就是经典的斜率方程

在每次求dp[i]时我们已经得出了dp[j]和dp[k],则可以得到二维坐标(T[j],f[j]),(T[k],f[k])。

会发现,如果还存在一个点y,y<k,且$(f[k]-f[y])/(T[k]-T[y])>=x[i]$,则k点可以直接被pass掉,在二维坐标中,就是维护一个下凸包点集。

这样就可以使得每次最优转移点可以O(1)得到,程序复杂度为O(n)。

 

技术图片
 1 #include<bits/stdc++.h>
 2 #define lson l,mid,i<<1
 3 #define rson mid+1,r,i<<1|1
 4 using namespace std;
 5 typedef long long ll;
 6 const int maxn = 1e6 + 10;
 7 ll c[maxn], x[maxn], p[maxn];
 8 ll sump[maxn];
 9 ll sumpx[maxn];
10 ll dp[maxn];
11 ll q[maxn];
12 ll check1(int j, int k) 
13     return dp[j] + sumpx[j] - dp[k] - sumpx[k];
14 
15 ll check2(int j, int k) 
16     return sump[j] - sump[k];
17 
18 int main() 
19     int n;
20     scanf("%d", &n);
21     for (int i = 1; i <= n; i++)
22         scanf("%lld%lld%lld", &x[i], &p[i], &c[i]);
23     for (int i = 1; i <= n; i++)
24         sump[i] = sump[i - 1] + p[i], sumpx[i] = sumpx[i - 1] + p[i] * x[i];
25     int l = 1, r = 1;
26     q[l] = 0;
27     for (int i = 1; i <= n; i++) 
28         while (l < r&&check1(q[l + 1], q[l]) <= x[i] * check2(q[l + 1], q[l]))
29             l++;
30         dp[i] = dp[q[l]] + c[i] + (sump[i - 1] - sump[q[l]])*x[i] - (sumpx[i - 1] - sumpx[q[l]]);
31         while (l < r&&check1(q[r], q[r - 1])*check2(i, q[r]) >= check1(i, q[r])*check2(q[r], q[r - 1]))
32             r--;
33         q[++r] = i;
34     
35     printf("%lld\n", dp[n]);
36     return 0;
37 
View Code

 

 

以上是关于[Bzoj1096][ZJOI2007]仓库建设(斜率优化)的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1096-[ZJOI2007]仓库建设

BZOJ 1096 [ZJOI2007]仓库建设 (斜率优化)

bzoj1096: [ZJOI2007]仓库建设

bzoj1096[ZJOI2007]仓库建设 斜率优化dp

bzoj1096 [ZJOI2007]仓库建设

BZOJ1096: [ZJOI2007]仓库建设