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

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

时间: 2024-10-24 16:10:39

BZOJ 1492: [NOI2007]货币兑换Cash( dp + 平衡树 )的相关文章

bzoj 1492 [NOI2007]货币兑换Cash(斜率dp+cdq分治)

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

[BZOJ 1492][NOI2007]货币兑换Cash(CDQ分治+斜率优化Dp)

Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目.我们记录第 K 天中 A券 和 B券 的 价值分别为 AK 和 BK(元/单位金券).为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易法 .比例交易法分为两个方面:(a)卖出金券:顾客提

bzoj 1492: [NOI2007]货币兑换Cash

Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目.我们记录第 K 天中 A券 和 B券 的 价值分别为 AK 和 BK(元/单位金券).为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易法 .比例交易法分为两个方面:(a)卖出金券:顾客提

【BZOJ】1492: [NOI2007]货币兑换Cash(cdq分治)

http://www.lydsy.com/JudgeOnline/problem.php?id=1492 蒟蒻来学学cdq神算法啊.. 详见论文 陈丹琦<从<Cash>谈一类分治算法的应用> orz 此题表示被坑精度.....导致没1a...开小号交了几发....................坑. 蒟蒻就说说自己的理解吧.. 首先这题神dp...(表示完全看不出来) 首先我们要最大化钱,那么可以将问题转化为最大化A券!(或B券)!!!!这点太神了,一定要记住这些!! 设d[i]表

1492: [NOI2007]货币兑换Cash

Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目.我们记录第 K 天中 A券 和 B券 的 价值分别为 AK 和 BK(元/单位金券).为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易法 .比例交易法分为两个方面:(a)卖出金券:顾客提

【BZOJ 1492】 [NOI2007]货币兑换Cash

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1948  Solved: 879 [Submit][Status][Discuss] Description Input 第一行两个正整数N.S,分别表示小Y 能预知的天数以及初始时拥有的钱数. 接下来N 行,第K 行三个实数AK.BK.RateK,意义如题目中所述 Output 只有一个实数MaxProfit,表示第N 天的操作结束时能够获得的最大的金

bzoj千题计划237:bzoj1492: [NOI2007]货币兑换Cash

http://www.lydsy.com/JudgeOnline/problem.php?id=1492 dp[i] 表示 第i天卖完的最大收益 朴素的dp: 枚举从哪一天买来的在第i天卖掉,或者是不操作 dp[i]=max(dp[i-1],X[j]*A[i]+Y[j]*B[i]) 其中X[j]表示在第j天能买多少A纪念券,Y[j]表示在第j天能买多少B纪念券 可列方程 X[j]*A[j]+Y[j]*B[j]=dp[j] 又因为 X[j]=Rate[j]*Y[j] 所以解出 Y[j]=dp[j]

bzoj [NOI2007]货币兑换Cash (cdq分治+斜率优化 )

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 2454  Solved: 1078 [Submit][Status][Discuss] Description Input 第一行两个正整数N.S,分别表示小Y 能预知的天数以及初始时拥有的钱数. 接下来N 行,第K 行三个实数AK.BK.RateK,意义如题目中所述 Output 只有一个实数MaxProfit,表示第N 天的操作结束时能够获得的最大的

bzoj1492[NOI2007]货币兑换Cash cdq分治+斜率优化dp

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5541  Solved: 2228[Submit][Status][Discuss] Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金