bzoj1597[Usaco2008 Mar]土地购买

bzoj1597[Usaco2008 Mar]土地购买

题意:

n块土地,现在要求把土地分成几份,每份费用为该份中土地长最大值和宽最大值成绩,要求最小费用。n≤5000

题解:

当一块土地长宽都比另一块土地小时,这块土地可以当作另一块土地的附属品,对答案不影响。因此先按长第一关键字,宽第二关键字排序,然后用单调队列就可以把长宽都被覆盖的土地除去。之后剩在单调队列里的土地长是升序排列,宽是降序排列,故用斜率优化dp:f[i]=max(f[j]+长[i]*宽[j+1]),j比k好当且仅当(f[j]-f[k])/(宽[k+1]-宽[j+1])<长[i]。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 50100
 6 #define ll long long
 7 using namespace std;
 8 
 9 struct str{ll x,y;}; str strs1[maxn],strs2[maxn];
10 bool cmp(str a,str b){return a.x!=b.x?a.x<b.x:a.y<b.y;}
11 inline int read(){
12     char ch=getchar(); int f=1,x=0;
13     while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
14     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
15     return f*x;
16 }
17 int n,l,r,m,q[maxn]; ll f[maxn];
18 double calc(int j,int k){
19     return (double)(f[j]-f[k])/(double)(strs2[k+1].y-strs2[j+1].y);
20 }
21 int main(){
22     n=read(); inc(i,1,n)strs1[i].x=(ll)read(),strs1[i].y=(ll)read(); sort(strs1+1,strs1+n+1,cmp); m=0;
23     inc(i,1,n){while(m&&strs2[m].y<=strs1[i].y)m--; strs2[++m]=strs1[i];} l=1; r=1; q[l]=0;
24     inc(i,1,m){
25         while(l<r&&calc(q[l],q[l+1])<strs2[i].x)l++; f[i]=f[q[l]]+strs2[i].x*strs2[q[l]+1].y;
26         while(l<r&&calc(q[r-1],q[r])>calc(q[r],i))r--; q[++r]=i;
27     }
28     printf("%lld",f[m]); return 0;
29 }

 

20160612

posted @ 2016-08-17 14:12  YuanZiming  阅读(187)  评论(0编辑  收藏  举报