1. 程式人生 > >BZOJ1597: [Usaco2008 Mar]土地購買

BZOJ1597: [Usaco2008 Mar]土地購買

zoj ace truct str logs typedef qsort namespace 我們

【傳送門:BZOJ1597】


簡要題意:

  給出n塊土地,給出每塊土地的長和寬,可以將n塊土地分成若幹組,每一組的費用是組中的長最大的土地的長與寬最大的土地的寬的乘積,求出將n塊分成若幹組的最小費用


題解:

  首先我們將一些土地排除,排除哪些土地呢?

  先將土地按長度遞增排序,然後長度相同按寬度遞增排序

  然後排除一些長與寬都能被任意土地包含的土地,把這些土地去掉,並不影響答案

  首先想到DP,f[i]表示將i塊土地分組後的最小值,因為我們排序了,而且排除了一些重合的情況後,得到的土地排序肯定是長度遞增而且寬度遞減的,所以很容易得到DP方程f[i]=min(f[j]+s[i].x*s[j+1].y),s結構體記錄土地的長和寬(x為長,y為寬),但是時間復雜度O(n2

),會超時

  那麽就用斜率優化來優化


參考代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long LL;
struct node
{
    LL x,y;
}a[51000],s[51000];
int cmp(const void *xx,const void *yy)
{
    node n1
=*(node *)xx; node n2=*(node *)yy; if(n1.x<n2.x) return -1; if(n1.x>n2.x) return 1; if(n1.y<n2.y) return -1; if(n1.y>n2.y) return 1; return 0; } /* f[i]=min(f[j]+s[i].x*s[j+1].y) j1<j2<i f[j2]+s[i].x*s[j2+1].y<=f[j1]+s[i].x*s[j1+1].y (f[j2]-f[j1])/(s[j1+1].y-s[j2+1].y)<=s[i].x
*/ LL f[51000]; double slop(int j1,int j2) { return (f[j2]-f[j1])/(s[j1+1].y-s[j2+1].y); } int list[51000]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld%lld",&a[i].x,&a[i].y); qsort(a+1,n,sizeof(node),cmp); int len=0; s[1]=a[1];len=1; for(int i=2;i<=n;i++) { while(len>0&&a[i].y>=s[len].y) len--; s[++len]=a[i]; } memset(f,0,sizeof(f)); int head=1,tail=1;list[1]=0; for(int i=1;i<=len;i++) { while(head<tail&&slop(list[head],list[head+1])<=double(s[i].x)) head++; int j=list[head]; f[i]=f[j]+s[i].x*s[j+1].y; while(head<tail&&slop(list[tail-1],list[tail])>slop(list[tail],i)) tail--; list[++tail]=i; } printf("%lld\n",f[len]); return 0; }

BZOJ1597: [Usaco2008 Mar]土地購買