[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 ...
随机推荐
- Pku1149 PIGS 卖猪
题目链接:ヾ(≧∇≦*)ゝ Description Emmy在一个养猪场工作.这个养猪场有M个锁着的猪圈,但Emmy并没有钥匙. 顾客会到养猪场来买猪,一个接着一个.每一位顾客都会有一些猪圈的钥匙,他 ...
- JavaScript匿名函数知多少
在一些Javascript库中可以看见这种写法: function(){ //所有库代码代码 }(); 这样写的一个目的是——封装. JavaScript并不是面向对象的,所以它不支持封装.但是在不支 ...
- C#线程篇---让你知道什么是线程(1)
线程线程,进程进程,到底什么是线程,什么是熟练多线程编程? 今天来和大家一起讨论讨论线程基础,让大家知道线程的基本构造. 说线程之前,先要了解下进程,这个可不能不知道. 什么是进程? Microsof ...
- 自定义ribbon规则
关于ribbon的知识:. 在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的.Spring cloud有两种服务调用方式,一种是ribbon+restT ...
- bzoj 5301 [Cqoi2018]异或序列 莫队
5301: [Cqoi2018]异或序列 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 204 Solved: 155[Submit][Status ...
- Python【异常处理】
def f(): first = input('请输入除数:') second = input('请输入被除数:') try: first = int(first) second = int(seco ...
- [leetcode]multiply-strings java代码
题目: Given two numbers represented as strings, return multiplication of the numbers as a string. Note ...
- Java基础之疑难知识点
问题列表: 1. Java中子类中可以有与父类相同的属性名吗? 2. Java中子类继承了父类的私有属性及方法吗? 3. Java中抽象类到底能不能被实例化? 1. Java中子类中可以有与父类相同的 ...
- caffe 配置文件详解
主要是遇坑了,要记录一下. solver算是caffe的核心的核心,它协调着整个模型的运作.caffe程序运行必带的一个参数就是solver配置文件.运行代码一般为 # caffe train --s ...
- bzoj千题计划166:bzoj2179: FFT快速傅立叶
http://www.lydsy.com/JudgeOnline/problem.php?id=2179 FFT做高精乘 #include<cmath> #include<cstdi ...