1. 程式人生 > >bzoj1597/luogu2900 土地購買 (斜率優化dp)

bzoj1597/luogu2900 土地購買 (斜率優化dp)

namespace fine int style 我們 一點 esp std ()

首先按x從小到大排序,那麽可得:

f[i]=min{f[j]+x[i]*maxy[j+1..i]}

然而這樣是$O(n^2)$的而且無法做優化。

然後我們考慮:如果對於某一點,存在另一點的x和y都比它大,那這個點是可以刪掉不參與計算的(因為那個較大的點一定要被買,那只要把這兩點放在一組裏,較小的點是絕對不會被算到的)

然後就可以發現,隨著x[i]單調增,y[i]是單調減的

那剛才的式子就可以變成f[i]=min{f[j]+x[i]*y[j+1]}了,於是就可以做斜率優化了。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4
#define LL long long int 5 using namespace std; 6 const int maxn=50050; 7 8 int rd(){ 9 int x=0;char c=getchar(); 10 while(c<0||c>9) c=getchar(); 11 while(c>=0&&c<=9) x=x*10+c-0,c=getchar(); 12 return x; 13 } 14 15 struct Node{ 16 int x,y; 17 }p[maxn];
18 int N,q[maxn],h,t; 19 LL x[maxn],y[maxn],f[maxn]; 20 bool deled[maxn]; 21 22 inline bool cmp(Node a,Node b){ 23 return a.x==b.x?a.y<b.y:a.x<b.x; 24 } 25 26 inline bool judge1(int j1,int j2,int i){ 27 return f[j1]-f[j2]<x[i]*(y[j2+1]-y[j1+1]); 28 } 29 inline bool judge2(int j1,int
j2,int j3){ 30 return (f[j1]-f[j2])*(y[j2+1]-y[j3+1])>(f[j2]-f[j3])*(y[j1+1]-y[j2+1]); 31 } 32 33 int main(){ 34 int i,j,k; 35 N=rd(); 36 for(i=1;i<=N;i++) p[i].x=rd(),p[i].y=rd(); 37 sort(p+1,p+N+1,cmp); 38 for(i=N;i;i=j){ 39 for(j=i-1;j&&p[j].y<p[i].y;j--) deled[j]=1; 40 }for(i=1,j=0;i<=N;i++){ 41 if(!deled[i]) x[++j]=p[i].x,y[j]=p[i].y; 42 }N=j; 43 q[h=t=1]=0; 44 for(i=1;i<=N;i++){ 45 while(h<t&&!judge1(q[h],q[h+1],i)) h++; 46 f[i]=f[q[h]]+x[i]*y[q[h]+1]; 47 while(h<t&&!judge2(q[t-1],q[t],i)) t--; 48 q[++t]=i; 49 }printf("%lld",f[N]); 50 }

bzoj1597/luogu2900 土地購買 (斜率優化dp)