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
* 第一行: 最小的可行费用.
dp斜率优化
对土地(x1,y1)和(x2,y2),若x1≥x2且y1≥y2,则可忽略(x2,y2)
将土地按x升序y降序排序,忽略不必考虑的土地
f[i]=max{f[j]+x[i]*y[j+1]}(0<j<i)
若k优于j则f[j]-f[k]>x[i]*(y[k+1]-y[j+1])
#include<cstdio> #include<algorithm> struct pos{ long long x,y; }vs[50001],ps[50001]; int pp=1; bool operator<(pos a,pos b){ if(a.x==b.x)return a.y<b.y; return a.x<b.x; } long long f[50001]; int q[50001]={0}; int qs=0,qe=0; int n; inline long long A(int x,int y){ return f[x]-f[y]; } inline long long B(int x,int y){ return ps[y+1].y-ps[x+1].y; } int main(){ scanf("%d",&n); for(int i=0;i<n;i++)scanf("%d%d",&vs[i].x,&vs[i].y); std::sort(vs,vs+n); for(int i=0;i<n;i++){ while(pp>1&&ps[pp-1].y<=vs[i].y)--pp; ps[pp++]=vs[i]; } for(int i=1;i<pp;i++){ while(qs<qe&&A(q[qs],q[qs+1])>ps[i].x*B(q[qs],q[qs+1]))++qs; int w=q[qs]; f[i]=f[w]+ps[i].x*ps[w+1].y; while(qs<qe&&A(q[qe-1],q[qe])*B(q[qe],i)>=A(q[qe],i)*B(q[qe-1],q[qe]))--qe; q[++qe]=i; } printf("%lld",f[pp-1]); return 0; }