[bzoj1492][NOI2007]Cash[CDQ分治;dp;斜率优化]
首先,设f[x]表示x天能获得的A券最大值,有动规方程:
$f[i]=max\{f[j]*A[i]+f[j]*B[i]/R[j]\}*R[i]/(R[i]*A[i]+B[i])$,
设 $j<k$ ,$f[j]>f[k]$
$\Rightarrow (f[j]/R[j]-f[k]/R[k])/(f[j]-f[k]) \leftarrow A[i]/B[i]$
令$g[i]=f[i]/R[i]$,则有$(g[j]-g[k])/(f[j]-f[k]) \leftarrow A[i]/B[i]$
将每一天描述为一个点$(f[i],g[i])$可以在一个上凸壳上进行二分进行斜率优化。
CDQ分治中按f[x]排序,分治时按id分割,这样用一个凸壳从左向右扫一遍,就可以更新整个区间的答案。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cmath> 7 #include <ctime> 8 9 using namespace std; 10 11 struct node 12 { 13 double x,y,A,B,R,k; int pos; 14 bool operator<(const node temp)const { return k>temp.k; } 15 }c[110000],temp[110000]; 16 17 int n,head,tail,H[110000]; 18 double f[110000]; 19 20 const double eps=1e-9; 21 22 double Calc(const int x,const int y) 23 { 24 if(fabs(c[x].x-c[y].x)<eps)return 1e100; 25 return (c[x].y-c[y].y)/(c[x].x-c[y].x); 26 } 27 28 void CDQ(const int l,const int r) 29 { 30 if(l==r) 31 { 32 f[l]=max(f[l],f[l-1]); 33 c[l].y=f[l]/(c[l].R*c[l].A+c[l].B);c[l].x=c[l].y*c[l].R; 34 return ; 35 } 36 37 int i,mid=l+((r-l)>>1); 38 39 int l1=l,l2=mid+1; 40 for(i=l;i<=r;++i) 41 { 42 if(c[i].pos<=mid)temp[l1++]=c[i]; 43 else temp[l2++]=c[i]; 44 } 45 for(i=l;i<=r;++i)c[i]=temp[i]; 46 47 CDQ(l,mid); 48 49 tail=0,head=1; 50 for(i=l;i<=mid;++i) 51 { 52 while(tail>1 && Calc(H[tail-1],H[tail])<Calc(H[tail],i))tail--; 53 H[++tail]=i; 54 } 55 for(i=mid+1;i<=r;++i) 56 { 57 while(head<tail && Calc(H[head],H[head+1])>c[i].k)head++; 58 f[c[i].pos]=max(f[c[i].pos],c[H[head]].x*c[i].A+c[H[head]].y*c[i].B); 59 } 60 61 CDQ(mid+1,r); 62 63 l1=l;l2=mid+1; 64 for(i=l;i<=r;++i) 65 { 66 if((c[l1].x<c[l2].x || (fabs(c[l1].x-c[l2].x)<eps && c[l1].y<c[l2].y+eps) || l2>r) && l1<=mid) 67 temp[i]=c[l1++]; 68 else 69 temp[i]=c[l2++]; 70 } 71 for(i=l;i<=r;++i)c[i]=temp[i]; 72 return ; 73 } 74 75 int main() 76 { 77 scanf("%d%lf",&n,&f[0]); 78 for(int i=1;i<=n;++i) 79 { 80 scanf("%lf%lf%lf",&c[i].A,&c[i].B,&c[i].R); 81 c[i].k=-c[i].A/c[i].B;c[i].pos=i; 82 } 83 84 sort(c+1,c+n+1); 85 86 CDQ(1,n); 87 88 printf("%.3f\n",f[n]); 89 90 return 0; 91 }