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 }
By Xs酱~ 转载请说明
博客地址:http://www.cnblogs.com/rausen