首先每次买卖一定是在某天 $k$ 以当时的最大收入买入,再到第 $i$ 天卖出,那么易得方程:

$$f_i = \max \{\frac{A_iRate_kf_k}{A_kRate_k + B_k} + \frac{B_if_k}{A_kRate_k + B_k}\}$$

再令

$$\left\{\begin{aligned} x_k = \frac{Rate_kf_k}{A_kRate_k + B_k} \\ y_k = \frac{f_k}{A_kRate_k + B_k}\end{aligned}\right.$$

则有

$$\begin{aligned} f_i &= \max \{A_ix_k + B_iy_k\} \\ y_k &= - \frac{A_i}{B_i}x_k + \frac{f_i}{B_i} \end{aligned}$$

那么现在需要找到一个点 $(x_k, y_k)$ 使得直线的截距最大

由于斜率和横坐标皆不满足单调性,可以用平衡树等维护,这里使用CDQ分治实现

实现过程如下:

Ⅰ 将数据按照斜率$\frac{A_i}{B_i}$降序排序

Ⅱ 将区间按照操作顺序分为左右两部分处理

Ⅲ 先处理左半部分,维护左半边凸包(注意,此时左半边已按照 $x$ 排序)

Ⅳ 处理左半边对右半边的影响,由于已按照斜率降序排序,所以普通斜率优化即可

Ⅴ 将区间按照 $x$ 排序

代码

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath> using namespace std; const int MAXN = 1e05 + ; const double INF = 1e60;
const double eps = 1e-; int Dcmp (double p) {
if (fabs (p) < eps)
return ;
return p < ? - : ;
} struct CashSt {
double a, b, rate;
double k, x, y;
int index; CashSt () {} bool operator < (const CashSt& p) const {
return Dcmp (x - p.x) == ? Dcmp (y - p.y) < : Dcmp (x - p.x) < ;
}
} ;
CashSt Cash[MAXN];
bool comp (const CashSt& a, const CashSt& b) {
return Dcmp (a.k - b.k) > ;
} int N; double slope (CashSt a, CashSt b) {
if (Dcmp (b.x - a.x) == )
return INF;
return (b.y - a.y) / (b.x - a.x);
}
double f[MAXN]= {};
CashSt Que[MAXN];
int l = , r = ;
CashSt temp[MAXN];
void CDQ (int left, int right) {
if (left == right) {
f[left] = max (f[left], f[left - ]);
Cash[left].y = f[left] / (Cash[left].a * Cash[left].rate + Cash[left].b);
Cash[left].x = Cash[left].y * Cash[left].rate;
return ;
}
int mid = (left + right) >> ;
int p1 = left - , p2 = mid;
for (int i = left; i <= right; i ++)
Cash[i].index <= mid ? temp[++ p1] = Cash[i] : temp[++ p2] = Cash[i];
for (int i = left; i <= right; i ++)
Cash[i] = temp[i];
CDQ (left, mid);
l = , r = ;
for (int i = left; i <= mid; i ++) {
while (l < r && Dcmp (slope (Que[r - ], Que[r]) - slope (Que[r], Cash[i])) < )
r --;
Que[++ r] = Cash[i];
}
for (int i = mid + ; i <= right; i ++) {
while (l < r && Dcmp (slope (Que[l], Que[l + ]) - Cash[i].k) > )
l ++;
f[Cash[i].index] = max (f[Cash[i].index], Cash[i].a * Que[l].x + Cash[i].b * Que[l].y);
}
CDQ (mid + , right);
l = left, r = mid + ;
int p = ;
while (l <= mid && r <= right) {
// if (Dcmp (Cash[l].x - Cash[r].x) < 0 || (Dcmp (Cash[l].x - Cash[r].x) == 0 && Dcmp (Cash[l].y - Cash[r].y) < 0))
if (Cash[l] < Cash[r])
temp[++ p] = Cash[l], l ++;
else
temp[++ p] = Cash[r], r ++;
}
while (l <= mid)
temp[++ p] = Cash[l], l ++;
while (r <= right)
temp[++ p] = Cash[r], r ++;
for (int i = ; i <= p; i ++)
Cash[i + left - ] = temp[i];
} double getnum () {
double num = 0.0;
char ch = getchar ();
double T = 1.0; while (! isdigit (ch))
ch = getchar ();
while (isdigit (ch))
num = num * 10.0 + (ch - '') * 1.0, ch = getchar ();
if (ch == '.') {
ch = getchar ();
while (isdigit (ch))
num = num + (T /= 10.0) * (ch - ''), ch = getchar ();
} return num;
} int main () {
// freopen ("Input.txt", "r", stdin); scanf ("%d%lf", & N, & f[]);
for (int i = ; i <= N; i ++) {
double a = getnum (), b = getnum (), rate = getnum ();
Cash[i].a = a, Cash[i].b = b, Cash[i].rate = rate;
Cash[i].index = i;
Cash[i].k = - a / b;
}
sort (Cash + , Cash + N + , comp);
CDQ (, N);
printf ("%.3f\n", f[N]); return ;
} /*
3 100
1 1 1
1 2 2
2 2 3
*/

[NOI2007]货币兑换 「CDQ分治实现斜率优化」的更多相关文章

  1. LOJ 2353 & 洛谷 P4027 [NOI2007]货币兑换(CDQ 分治维护斜率优化)

    题目传送门 纪念一下第一道(?)自己 yy 出来的 NOI 题. 考虑 dp,\(dp[i]\) 表示到第 \(i\) 天最多有多少钱. 那么有 \(dp[i]=\max\{\max\limits_{ ...

  2. BZOJ1492: [NOI2007]货币兑换Cash(CDQ分治,斜率优化动态规划)

    Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个 ...

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

    [BZOJ1492] [NOI2007] 货币兑换Cash(cdq分治+斜率优化) 题面 分析 dp方程推导 显然,必然存在一种最优的买卖方案满足:每次买进操作使用完所有的人民币:每次卖出操作卖出所有 ...

  4. Codeforces Gym 101175F - Machine Works(CDQ 分治维护斜率优化)

    题面传送门 首先很明显我们会按照 \(d_i\) 的顺序从小到大买这些机器,故不管三七二十一先将所有机器按 \(d_i\) 从小到大排序. 考虑 \(dp\),\(dp_i\) 表示在时刻 \(d_i ...

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

    1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5541  Solved: 2228[Submit][Sta ...

  6. [NOI2007]货币兑换 cdq分治,斜率优化

    [NOI2007]货币兑换 LG传送门 妥妥的\(n \log n\)cdq做法. 这题用cdq分治也可以\(n \log n\)但是在洛谷上竟然比一些优秀的splay跑得慢真是见了鬼了看来还是人丑常 ...

  7. BZOJ1492:[NOI2007]货币兑换 (CDQ分治+斜率优化DP | splay动态维护凸包)

    BZOJ1492:[NOI2007]货币兑换 题目传送门 [问题描述] 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和B纪念券(以下简称B券).每个持有金券的 ...

  8. BZOJ 1492: [NOI2007]货币兑换Cash [CDQ分治 斜率优化DP]

    传送门 题意:不想写... 扔链接就跑 好吧我回来了 首先发现每次兑换一定是全部兑换,因为你兑换说明有利可图,是为了后面的某一天两种卷的汇率差别明显而兑换 那么一定拿全利啊,一定比多天的组合好 $f[ ...

  9. Bzoj1492: [NOI2007]货币兑换Cash(不单调的斜率优化)

    题面 传送门 Sol 题目都说了 必然存在一种最优的买卖方案满足: 每次买进操作使用完所有的人民币: 每次卖出操作卖出所有的金券. 设\(f[i]\)表示第\(i\)天可以有的最大钱数 枚举\(j&l ...

随机推荐

  1. MT【130】Heilbronn问题

    (清华THUSSAT,多选题) 平面上 4 个不同点 \(P_1,P_2,P_3,P_4\),在每两个点之间连接线段得到 6 条线段. 记 \[L=\max_{1\leq i<j\leq 4}| ...

  2. MT【117】立体几何里的一道分类讨论题

    评:最后用到了中间的截面三角形两边之和大于第三边.能不能构成三棱锥时考虑压扁的"降维"打击是常见的方式.

  3. hdu2138 Miller_Rabin

    Description   Give you a lot of positive integers, just to find out how many prime numbers there are ...

  4. BZOJ 3165: [Heoi2013]Segment

    3165: [Heoi2013]Segment Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 465  Solved: 187[Submit][Sta ...

  5. 【CF835D】Palindromic characteristics 加强版 解题报告

    [CF835D]Palindromic characteristics 加强版 Description 给你一个串,让你求出\(k\)阶回文子串有多少个.\(k\)从\(1\)到\(n\). \(k\ ...

  6. 【费用流】【网络流24题】【P4013】 数字梯形问题

    Description 给定一个由 \(n\) 行数字组成的数字梯形如下图所示. 梯形的第一行有 \(m\) 个数字.从梯形的顶部的 \(m\) 个数字开始,在每个数字处可以沿左下或右下方向移动,形成 ...

  7. python之旅:模块与包

    一.模块介绍 前言:引用廖雪峰大神的,说的很好!!! 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放 ...

  8. beego 定义一个存储变量的容器

    golang 这种语言相对于 php 有个好处是,不用每次请求都重复一些不必要的初始化操作,golang 进程开启之后,即使请求结束,相关的资源也会驻留在内存中. 所以我们可以把一些不需要重复初始化的 ...

  9. pre-processing预处理

    什么是神经网络?神经网络是由很多神经元组成的,首先我们看一下,什么是神经元1.我们把输入信号看成你在matlab中需要输入的数据,输进去神经网络后2.这些数据的每一个都会被乘个数,即权值w,然后这些东 ...

  10. golang 中的 time 包的 Ticker

    真实的应用场景是:在测试收包的顺序的时候,加了个 tick 就发现丢包了 那么来看一个应用例子: package main import ( "fmt" "runtime ...