1. 程式人生 > >BZOJ1597: [Usaco2008 Mar]土地購買——斜率優化

BZOJ1597: [Usaco2008 Mar]土地購買——斜率優化

zoj ret 代碼 size Go long while AI UC

題目大意:

將$n$個長方形分成若幹部分,每一部分的花費為部分中長方形的$max_長*max_寬$(不是$max_{長*寬}$),求最小花費

思路:

首先,可以被其他長方形包含的長方形可以刪去

然後我們按長方形的長度從小到大排序(排序後的長方形的寬度一定是從大到小)

設$f(i)$表示前i個長方形的最小花費,長方形的長和寬分別為$x(i),y(i)$,則有方程

$\Large f(i)=min(f(j)+x(i)*y(j+1))$

若對於某個$i$有$j$比$k$優,則

$f(j)+x(i)*y(j+1)\le f(k)+x(i)*y(k+1)$

化簡得$\frac{f(j)-f(k)}{y(k+1)-y(j+1)}\le x(i)$

維護下凸殼即可

代碼

#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 50005
#define LL long long
struct Node{
    int x,y;
    bool operator < (const Node& a)const{
        return x!=a.x?x<a.x:y<a.y;
    }
}a[maxn];
int n,si,que[maxn],s,t=1;
LL f[maxn];
LL calc(
int i,int j){ return (f[i]-f[j]-1)/(a[j+1].y-a[i+1].y)+1; } void insert(int x){ while(s<t-1&&calc(x,que[t-1])<=calc(que[t-1],que[t-2]))t--; que[t++]=x; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%d",&a[i].x,&a[i].y); } sort(a
+1,a+n+1); for(int i=1;i<=n;i++){ while(si&&a[si].y<=a[i].y)si--; a[++si]=a[i]; }n=si; for(int i=1;i<=n;i++){ while(s<t-1&&calc(que[s+1],que[s])<=a[i].x)s++; int w=que[s]; f[i]=f[w]+1ll*a[i].x*a[w+1].y; insert(i); } printf("%lld",f[n]); return 0; }

BZOJ1597: [Usaco2008 Mar]土地購買——斜率優化