BZOJ[1597][Usaco2008 Mar]土地购买 斜率优化

传送门ber~

首先按 x 为第一关键字, y 为第二关键字,将没有贡献的矩形( x i < x j , y i < y j , i < j )删掉,这样就满足了 x 递增, y 递减,列出dp方程 f i = m i n { f j + y j + 1 x i }
t > k ,状态 t k 优,当且仅当

f t + y t + 1 x i < f k + y k + 1 x i

因为 y 递减,所以 y k + 1 y t + 1 > 0 ,那么
f t f k y k + 1 y t + 1 < x i
f t f k y t + 1 y k + 1 > x i

所以维护一个上凸壳,坐标为 ( y i + 1 , f i ) ,斜率优化。
x 是单调的,所以单调队列维护

代码如下:

#include<algorithm>
#include<ctype.h>
#include<cstdio>
#define INF 21474836470000ll
#define N 50050
using namespace std;
typedef long long LL;
inline int read(){
    int x=0,f=1;char c;
    do c=getchar(),f=c=='-'?-1:f; while(!isdigit(c));
    do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
    return x*f;
}
int n,l,r,tot;
LL f[N];
struct Point{
    LL x,y;
    Point(){}
    Point(LL _,LL __):x(_),y(__){}
}q[N],a[N],b[N],tmp;
inline bool cmp(Point a,Point b){
    return a.x==b.x?a.y<b.y:a.x<b.x;
}
inline double Slop(Point a,Point b){
    if(a.x==b.x) return a.y>b.y?-INF:INF;
    return 1.0*(b.y-a.y)/(b.x-a.x);
}
int main(){
    n=read();
    for(int i=1;i<=n;i++){
        b[i].x=read();b[i].y=read();
    }
    sort(b+1,b+n+1,cmp);
    for(int i=1;i<=n;i++){
        while(tot && b[i].y>=a[tot].y) tot--;
        a[++tot]=b[i];
    }
    l=r=0;
    q[0]=Point(a[1].y,0);
    for(int i=1;i<=tot;i++){
        while(l<r && Slop(q[l],q[l+1])>-a[i].x) l++;
        f[i]=a[i].x*q[l].x+q[l].y;
        tmp=Point(a[i+1].y,f[i]);
        while(l<r && Slop(q[r],tmp)>Slop(q[r-1],q[r])) r--;
        q[++r]=tmp;
    }
    printf("%lld",f[tot]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/waduan2/article/details/79723450