题目描述
Farmer John 准备扩大他的农场,眼前他正在考虑购买 N 块长方形的土地。
如果 FJ 单买一块土地,价格就是土地的面积。但他可以选择并购一组土地,并购的价格为这些土地中最大的长乘以最大的宽。比如 FJ 并购一块 3×5 和一块 5×3 的土地,他只需要支付 5×5=25 元, 比单买合算。
FJ 希望买下所有的土地。他发现,将这些土地分成不同的小组来并购可以节省经费。 给定每份土地的尺寸,请你帮助他计算购买所有土地所需的最小费用。
输入格式
第一行一个整数 N(1≤N≤5×10^4)。
接下来 N 行,每行两个整数 w_i 和 l_i,代表第 i 块土地的长和宽。保证土地的长和宽不超过 10^6。
输出格式
输出买下所有土地的最小费用。
输入输出样例
4 100 1 15 15 20 5 1 100
说明/提示
将所有土地分为三组:
- 第一块土地为第一组,花费 100×1=100;
- 第二,三块土地为第二组,花费 20×15=300;
- 第四块土地为第三组,花费 1×100=100;
总花费为 500,可以证明不存在更优的方案。
________________________________________
简单的斜率优化动态规划
首先,如果一块的长宽都大于等于另一块地,那么另一块地是不需要交钱的。所以先把所有的土地按照长从大到小排序,如果后面的土地的宽度小于前面某块大的,则不需考虑。
剩余的土地的宽逐步减小,而长逐渐增加的(减小的都不用考虑)。
建立简单的动态规划:f[i]=min(f[j]+h[i]*w[j+1])
这个动归要依次从大到小枚举i,而每个i要枚举j,所以明显是O(N^2),无法完成。
由于出现了h[i]*w[j+1],而求得是最小值,因此考虑斜率优化。
设:0<j<k<i,且k优于j
所以,f[j]+h[i]*w[j+1]>f[k]+h[i]*w[k+1]
移项可得:(f[k]-f[j])/(w[k+1]-w[j+1])>-h[i]
我们通过前面的排序可知:h[i]是逐渐变大的,所以-h[i]逐渐减小,具有单调性
然后就按照斜率优化做就可以了!
________________________________________
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=5e4+10; 4 struct node 5 { 6 long long w,h; 7 }sz[maxn]; 8 int n; 9 int q[maxn]; 10 long long f[maxn]; 11 bool cmp(node a,node b) 12 { 13 return a.w>b.w || a.w==b.w &&a.h>b.h; 14 } 15 long double y(int a) 16 { 17 return (double)f[a]; 18 } 19 long double x(int a) 20 { 21 return (double)sz[a+1].w; 22 } 23 long double get_xl(int a,int b) 24 { 25 return (y(b)-y(a))/(x(b)-x(a)); 26 } 27 28 int main() 29 { 30 scanf("%d",&n); 31 for(int i=1;i<=n;++i) 32 scanf("%lld%lld",&sz[i].w,&sz[i].h); 33 sort(sz+1,sz+1+n,cmp); 34 int nn=1; 35 for(int i=2;i<=n;++i) 36 if(sz[i].h>sz[nn].h)sz[++nn]=sz[i]; 37 int l,r; 38 l=r=0; 39 for(int i=1;i<=nn;++i) 40 { 41 while(l<r && get_xl(q[l],q[l+1])>=-sz[i].h)l++; 42 f[i]=f[q[l]]+sz[i].h*sz[q[l]+1].w; 43 while(l<r && get_xl(q[r-1],q[r])<=get_xl(q[r],i))--r; 44 q[++r]=i; 45 } 46 cout<<f[nn]<<endl; 47 return 0; 48 }