bzoj 1597 土地购买

Description

农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <
= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地的价格是它的面积,但FJ可以同时购买多快土地. 这些土地的价
格是它们最大的长乘以它们最大的宽, 但是土地的长宽不能交换. 如果FJ买一块3x5的地和一块5x3的地,则他需要
付5x5=25. FJ希望买下所有的土地,但是他发现分组来买这些土地可以节省经费. 他需要你帮助他找到最小的经费.

Input

* 第1行: 一个数: N
* 第2..N+1行: 第i+1行包含两个数,分别为第i块土地的长和宽

Output

* 第一行: 最小的可行费用.

Sample Input

4
100 1
15 15
20 5
1 100
输入解释:
共有4块土地.

Sample Output

500
FJ分3组买这些土地:
第一组:100x1,
第二组1x100,
第三组20x5 和 15x15 plot.
每组的价格分别为100,100,300, 总共500.

HINT

 

思路 :这个题目是一个斜率优化的dp,我们先把初始的土地预处理一下,让土地的h递增,w递减,其他一些土地长宽都比某些土地小,这些土地是不会影响答案的。

然后我们设f[i]表示前i个土地的最小费用。

易证,f[i]=min(f[j]+h[i]*w[j+1]); 为了计算方便,将w数组错一位,f[i]=min(f[j]+h[i]*w[j]); 考虑两个转移f[j],f[k],且k<j<i ; 若对于f[i]从f[j]转移比从f[k]转移更优,那么f[j]+h[i]*w[j]<f[k]+h[i]*w[k];  

根据线性规划的知识和斜率的知识,我们维护一个斜率不断减小的凸包,答案一定在凸包的点上。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define R register int
 4 #define rep(i,a,b) for(R i=a;i<=b;i++)
 5 #define Rep(i,a,b) for(R i=a;i>=b;i--)
 6 #define ms(i,a)    memset(a,i,sizeof(a))
 7 #define gc()       getchar()
 8 #define LL         long long
 9 template<class T>void read(T &x){
10   x=0; char c=0;
11   while (!isdigit(c)) c=gc();
12   while (isdigit(c)) x=x*10+(c^48),c=gc();
13 }
14 int const N=50000+3;
15 int q[N],n,st[N],top,m;
16 LL dp[N],h[N],w[N];
17 struct node{
18   int h,w;
19   bool operator < (const node &rhs) const{
20     if(h!=rhs.h) return h<rhs.h;
21     return w>rhs.w; 
22   }
23 }a[N];
24 int main(){
25   read(n);
26   rep(i,1,n) read(a[i].h),read(a[i].w);
27   sort(a+1,a+n+1);
28   st[top=1]=1;
29   rep(i,2,n)if(a[i].h!=a[i-1].h){
30     while (top && a[i].w>=a[st[top]].w) top--;
31     st[++top]=i;
32   }
33   m=top;
34   w[0]=a[st[1]].w;
35   rep(i,1,m) h[i]=a[st[i]].h,w[i]=a[st[i+1]].w;
36   int st=0,ed=0;
37   rep(i,1,m){
38     while (st<ed && dp[q[st+1]]-dp[q[st]]<h[i]*(w[q[st]]-w[q[st+1]])) st++;
39     dp[i]=dp[q[st]]+h[i]*w[q[st]];
40     while (st<ed && (dp[i]-dp[q[ed]])*(w[q[ed]]-w[q[ed-1]])>(dp[q[ed]]-dp[q[ed-1]])*(w[i]-w[q[ed]])) ed--;
41     q[++ed]=i;
42   }
43   cout<<dp[m]<<endl;
44   return 0;
45 }
View Code

 

posted @ 2019-01-03 01:13  zjxxcn  阅读(95)  评论(0编辑  收藏  举报