CDQ分治的例题。。。

首先可以想到是动态规划,我们令f[i]表示第i天可以赚到的最大钱数,x[i]、y[i]表示f[i]取到最优的时候a、b券的最大值。

则f[i] = max(f[i - 1], a[i] * x[j] + b[i] * y[j]) (j  < i)

然后我们优化一下,对于

a * x[j] + b * y[j] < a * x[k] + b * y[k] 且 j < k  =>

a * (x[j] - x[k]) < b * (y[k] - y[j])  =>

a / b < - (y[j] - y[k]) / (x[j] - x[k])

于是我们发现可以斜率优化,维护上凸壳,结果发现x不单调,大家都很厉害会用平衡树维护,但是我就不会

然后就想到了CDQ分治什么的。。。

 

 1 /**************************************************************
 2     Problem: 1492
 3     User: rausen
 4     Language: C++
 5     Result: Accepted
 6     Time:1420 ms
 7     Memory:12140 kb
 8 ****************************************************************/
 9  
10 #include <cstdio>
11 #include <cmath>
12 #include <algorithm>
13  
14 using namespace std;
15 typedef double lf;
16 const lf inf = 1e20;
17 const lf eps = 1e-9;
18 const int N = 1e5 + 5;
19  
20 inline int sgn(lf x) {
21     return fabs(x) < eps ? 0 : x < 0 ? -1 : 1; 
22 }
23  
24 struct point {
25     lf x, y, a, b, k, rate;
26     int id;
27      
28     inline bool operator < (const point &p) const {
29         return sgn(x - p.x) == 0 ? sgn(y - p.y) < 0 : sgn(x - p.x) < 0;
30     }
31 } p[N], tmp[N];
32  
33 inline bool cmp(point p, point q) {
34     return p.k > q.k;
35 } 
36  
37 lf f[N];
38 int n, top, s[N];
39  
40 inline lf get(int a, int b) {
41     if (!b) return -inf;
42     return sgn(p[a].x - p[b].x) == 0 ? inf : (p[b].y - p[a].y) / (p[b].x - p[a].x);
43 }
44  
45 void work(int l, int r) {
46     if (l == r) {
47         f[l] = max(f[l], f[l - 1]);
48         p[l].y = f[l] / (p[l].a * p[l].rate + p[l].b);
49         p[l].x = p[l].rate * p[l].y;
50         return;
51     }
52     int i, j, l1, l2, mid = l + r >> 1;
53     for (i = l, l1 = l, l2 = mid + 1; i <= r; ++i)
54         if (p[i].id <= mid) tmp[l1++] = p[i];
55         else tmp[l2++] = p[i];
56     for (i = l; i <= r; ++i) p[i] = tmp[i];
57      
58     work(l, mid);
59     for (top = 0, i = l; i <= mid; ++i) {
60         while (top > 1 && sgn(get(s[top - 1], s[top]) - get(s[top], i)) < 0) --top;
61         s[++top] = i;
62     }
63     s[++top] = 0;
64     for (i = mid + 1, j = 1; i <= r; ++i) {
65         while (j < top && sgn(p[i].k - get(s[j], s[j + 1])) < 0) ++j;
66         f[p[i].id] = max(f[p[i].id], p[s[j]].x * p[i].a + p[s[j]].y * p[i].b);
67     }
68     work(mid + 1, r);
69      
70     for (i = l, l1 = l, l2 = mid + 1; i <= r; ++i)
71         if ((p[l1] < p[l2] || l2 > r) && l1 <= mid) tmp[i] = p[l1++];
72         else tmp[i] = p[l2++];
73     for (i = l; i <= r; ++i) p[i] = tmp[i];
74 }
75  
76 int main() {
77     int i;
78     scanf("%d%lf", &n, &f[0]);
79     for (i = 1; i <= n; ++i) {
80         scanf("%lf%lf%lf", &p[i].a, &p[i].b, &p[i].rate);
81         p[i].k = -p[i].a / p[i].b, p[i].id = i;
82     }
83     sort(p + 1, p + n + 1, cmp);
84     work(1, n);
85     printf("%.3lf\n", f[n]);
86     return 0;
87 }
View Code

 

posted on 2015-03-01 19:53  Xs酱~  阅读(214)  评论(0编辑  收藏  举报