您的位置:首页 > 其它

BZOJ 1492: [NOI2007]货币兑换Cash( dp + 平衡树 )

2016-01-24 15:12 447 查看


dp(i) = max(dp(i-1), x[j]*a[i]+y[j]*b[i]), 0<j<i. x, y表示某天拥有的最多钱去买金券, 金券a和金券b的数量. 然后就很明显了...平衡树维护上凸壳, 询问时就在凸壳上二分...时间复杂度O(NlogN)

-----------------------------------------------------------------------------------------------

#include<cmath>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm> using namespace std; #define K(a, b) ((a.y - b.y) / (a.x - b.x)) const int maxn = 100009;const double eps = 1e-7;const double INF = 1e100; double dp, A, B, R, K;int N; struct P { double x, y; P(double _x = 0, double _y = 0) : x(_x), y(_y) { } bool operator < (const P &p) const { return x < p.x; } bool operator == (const P &p) const { return fabs(x - p.x) < eps && fabs(y - p.y) < eps; }} p; struct Node { Node* ch[2]; double lk, rk; int r; P p;} pool[maxn], *pt, *Root, *Null; void Init_Treap() { pt = pool; pt->ch[0] = pt->ch[1] = pt; pt->p = P(-INF, -INF); Root = Null = pt++;} void Rotate(Node*&t, int d) { Node* o = t->ch[d ^ 1]; t->ch[d ^ 1] = o->ch[d]; o->ch[d] = t; t = o;} void Insert(Node*&t) { if(t == Null) { (t = pt++)->p = p, t->r = rand(); t->ch[0] = t->ch[1] = Null; } else { int d = (t->p < p); Insert(t->ch[d]); if(t->ch[d]->r > t->r) Rotate(t, d ^ 1); }} void Delete(Node*&t) { int d = (p == t->p ? -1 : (t->p < p)); if(d == -1) { if(t->ch[0] != Null && t->ch[1] != Null) { int _d = (t->ch[0]->r > t->ch[1]->r); Rotate(t, _d), Delete(t->ch[_d]); } else t = (t->ch[0] != Null ? t->ch[0] : t->ch[1]); } else Delete(t->ch[d]);} Node* Pred(P &p) { Node* ret = Null; for(Node* o = Root; o != Null; ) if(o->p < p) ret = o, o = o->ch[1]; else o = o->ch[0]; return ret;} Node* Succ(P &p) { Node* ret = Null; for(Node* o = Root; o != Null; ) if(p < o->p) ret = o, o = o->ch[0]; else o = o->ch[1]; return ret;} Node* Find(P &p) { for(Node* t = Root; t != Null; ) { if(fabs(t->p.x - p.x) < eps) return t; t = (p.x < t->p.x ? t->ch[0] : t->ch[1]); } return 0;} P Select(Node*&t) { if(t->r == -1) return Select(t->ch[1]); if(t->r == -2) return Select(t->ch[0]); if(K - t->lk < eps && t->rk - K < eps) return t->p; return K - t->lk > eps ? Select(t->ch[0]) : Select(t->ch[1]);} void Init() { Init_Treap(); p = P(0, -INF), Insert(Root); p = P(1e10, -INF), Insert(Root); Node* t = pt; (--t)->r = -2, (--t)->r = -1;} void Add() { double b = dp / (A * R + B), a = b * R; P o = P(a, b); Node *t = Find(o); if(t) { if(t->p.y - o.y > eps) return; p = t->p, Delete(Root); } Node *L = Pred(o), *R = Succ(o); if(R->p == o || K(o, R->p) - K(o, L->p) > eps) return; for(Node* LL = Pred(L->p); LL != Null; ) { if(K(o, L->p) - K(L->p, LL->p) > eps) p = L->p, Delete(Root); else break; L = LL, LL = Pred(L->p); } pt->lk = L->rk = K(L->p, o); for(Node* RR = Succ(R->p); RR != Null; ) { if(K(RR->p, R->p) - K(R->p, o) > eps) p = R->p, Delete(Root); else break; R = RR, RR = Succ(R->p); } R->lk = pt->rk = K(R->p, o); p = o, Insert(Root);} void Work() { scanf("%d%lf", &N, &dp); for(int i = 0; i < N; i++) { scanf("%lf%lf%lf", &A, &B, &R); if(i) { K = -A / B; P o = Select(Root); dp = max(dp, A * o.x + B * o.y); } Add(); } printf("%.3lf\n", dp);} int main() { Init(); Work(); return 0;}-----------------------------------------------------------------------------------------------

1492: [NOI2007]货币兑换Cash

Time Limit: 5 Sec Memory Limit: 64 MB
Submit: 2843 Solved: 1201
[Submit][Status][Discuss]

Description


Input

第一行两个正整数N、S,分别表示小Y 能预知的天数以及初始时拥有的钱数。 接下来N 行,第K 行三个实数AK、BK、RateK,意义如题目中所述

Output

只有一个实数MaxProfit,表示第N 天的操作结束时能够获得的最大的金钱 数目。答案保留3 位小数。

Sample Input

3 100
1 1 1
1 2 2
2 2 3

Sample Output

225.000

HINT



测试数据设计使得精度误差不会超过10-7。
对于40%的测试数据,满足N ≤ 10;
对于60%的测试数据,满足N ≤ 1 000;
对于100%的测试数据,满足N ≤ 100 000;

Source

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: