[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 }

 

posted @ 2015-12-31 02:57  Gster  阅读(439)  评论(0编辑  收藏  举报