[NOI2007]货币兑换 「CDQ分治实现斜率优化」
首先每次买卖一定是在某天 $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分治实现斜率优化」的更多相关文章
- LOJ 2353 & 洛谷 P4027 [NOI2007]货币兑换(CDQ 分治维护斜率优化)
题目传送门 纪念一下第一道(?)自己 yy 出来的 NOI 题. 考虑 dp,\(dp[i]\) 表示到第 \(i\) 天最多有多少钱. 那么有 \(dp[i]=\max\{\max\limits_{ ...
- BZOJ1492: [NOI2007]货币兑换Cash(CDQ分治,斜率优化动态规划)
Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个 ...
- [BZOJ1492] [NOI2007] 货币兑换Cash(cdq分治+斜率优化)
[BZOJ1492] [NOI2007] 货币兑换Cash(cdq分治+斜率优化) 题面 分析 dp方程推导 显然,必然存在一种最优的买卖方案满足:每次买进操作使用完所有的人民币:每次卖出操作卖出所有 ...
- Codeforces Gym 101175F - Machine Works(CDQ 分治维护斜率优化)
题面传送门 首先很明显我们会按照 \(d_i\) 的顺序从小到大买这些机器,故不管三七二十一先将所有机器按 \(d_i\) 从小到大排序. 考虑 \(dp\),\(dp_i\) 表示在时刻 \(d_i ...
- bzoj1492[NOI2007]货币兑换Cash cdq分治+斜率优化dp
1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 5541 Solved: 2228[Submit][Sta ...
- [NOI2007]货币兑换 cdq分治,斜率优化
[NOI2007]货币兑换 LG传送门 妥妥的\(n \log n\)cdq做法. 这题用cdq分治也可以\(n \log n\)但是在洛谷上竟然比一些优秀的splay跑得慢真是见了鬼了看来还是人丑常 ...
- BZOJ1492:[NOI2007]货币兑换 (CDQ分治+斜率优化DP | splay动态维护凸包)
BZOJ1492:[NOI2007]货币兑换 题目传送门 [问题描述] 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和B纪念券(以下简称B券).每个持有金券的 ...
- BZOJ 1492: [NOI2007]货币兑换Cash [CDQ分治 斜率优化DP]
传送门 题意:不想写... 扔链接就跑 好吧我回来了 首先发现每次兑换一定是全部兑换,因为你兑换说明有利可图,是为了后面的某一天两种卷的汇率差别明显而兑换 那么一定拿全利啊,一定比多天的组合好 $f[ ...
- Bzoj1492: [NOI2007]货币兑换Cash(不单调的斜率优化)
题面 传送门 Sol 题目都说了 必然存在一种最优的买卖方案满足: 每次买进操作使用完所有的人民币: 每次卖出操作卖出所有的金券. 设\(f[i]\)表示第\(i\)天可以有的最大钱数 枚举\(j&l ...
随机推荐
- [AT2567] [arc074_c] RGB Sequence
题目链接 AtCoder:https://arc074.contest.atcoder.jp/tasks/arc074_c 洛谷:https://www.luogu.org/problemnew/sh ...
- 【bzoj1087】互不侵犯King
Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包 ...
- 【BZOJ1858】序列操作(线段树)
[BZOJ1858]序列操作(线段树) 题面 BZOJ 题解 这题思路很简单,细节很烦,很码 维护区间翻转和区间赋值标记 当打到区间赋值标记时直接覆盖掉翻转标记 下放标记的时候先放赋值标记再放翻转标记 ...
- 【BZOJ4869】【SHOI2017】相逢是问候
Description BZOJ传送门 Solution 这题涉及到指数嵌套堆叠,可能可以用欧拉函数解决. 试想一个数\(a_i\)经过\(k\)次操作后会变成什么? \[ k个c\;\; \begi ...
- WEB入门.七 CSS布局模型
学习内容 标准文档流 流动模型(flow model) 浮动模型(float model) CSS基本布局 能力目标 理解标准文档流 使用流动模型实现页面布局 使用浮动模型实现页面布局 掌握常用CSS ...
- kibana使用(ELK)、Lucene 查询语法
Lucene查询 Lucene查询语法以可读的方式书写,然后使用JavaCC进行词法转换,转换成机器可识别的查询. 下面着重介绍下Lucene支持的查询: Terms词语查询 词语搜索,支持 单词 和 ...
- 解题:POI 2010 Beads
题面 正反各做一遍哈希来判断,然后在两个哈希值里取一个$max/min$做哈希值,然后每次把子串们的哈希插进$set$里,最后统计集合大小,就可以优秀地在$O(nlog^2$ $n)$中出解了 然后我 ...
- EL与OGNL以及值栈的理解
这里先添加下在项目遇到的问题: 这两天在做论坛项目的时候,犯了一个错误:将数据放入值栈中,结果jsp页面获取不到. 困扰了许久: 总结如下: (1)每个action对应相应页面的值栈中值的获取,在属于 ...
- 什么是Docker并且它为什么这么受欢迎
什么是Docker (why it's so hot than hot) Docker是一个使用容器来方便快捷的创建,部署,运行程序的工具,容器允许开发人员将应用程序的一切打包(镜像),例如库和其他的 ...
- 在Kubernetes集群里安装微服务DevOps平台fabric8
转载于https://blog.csdn.net/wzp1986/article/details/72128063?utm_source=itdadao&utm_medium=referral ...