码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-07-04 09:29:36      阅读:93      评论:0      收藏:0      [点我收藏+]

标签:img   凸包   仓库   mes   仓库建设   zjoi2007   tar   names   geo   

题目链接: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-1}p[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]仓库建设(斜率优化)

标签:img   凸包   仓库   mes   仓库建设   zjoi2007   tar   names   geo   

原文地址:https://www.cnblogs.com/sainsist/p/11130188.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!