Description

Input

第一行两个正整数\(N,S\),分别表示小Y 能预知的天数以及初始时拥有的钱数。 接下来\(N\)行,第\(K\)行三个实数\(A_{K},B_{K},Rate_{K}\),意义如题目中所述。

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 \le 10\);

对于60%的测试数据,满足\(N \le 1000\);

对于100%的测试数据,满足\(N \le 100000\)。

这是一道斜率优化dp的好题。他并不满足单调性,我们只能动态维护凸包。平衡树动态维护凸包并不好码,我们可以用编程复杂度较低的cdq分治。

首先确定一点:最优解一定是贪心地全部买入或卖出所得到的。

\(f_{i}\)表示第\(i\)天所能得到的最多钱数,转移:$$f_{i}=max(f_{i-1},A_{i} \times rate_{j} \frac{f_{j}}{1+rate_{j}}+B_{i} \times \frac{f_{j}}{1+rate_{j}})$$

但是对于这个式子dp是\(O(n^{2})\)的,我们可以令$$X_{i}= rate_{i} \frac{f_{i}}{1+rate_{i}},Y_{i}=\frac{f_{i}}{1+rate_{i}}$$

则dp方程就可以化简为$$f_{i}=max(f_{i-1},A_{j} \times X_{j}+B_{j} \times Y_{j})$$

看出来没,这是一个很明显的斜率优化dp的式子,但是\(X_{i}\)和\(Y_{i}\)都不单调,怎么办。

平衡树动态维护凸包,并不会。于是cdq分治的优势就体现出来了。

cdq分治:对于\(l \thicksim r\)一段,我们可以用已经算出来的\(l \thicksim mid\)一段区更新\(mid+1 \thicksim r\)一段。由于\(l \thicksim mid\)一段\(f\)已经确定,所以我们可以对之进行排序,求凸包之类的,借之更新\(mid+1 \thicksim r\)。

我们只需对于确定\(l \thicksim mid\)一段求凸包,然后用每个\(mid+1 \thicksim r\)里的元素进行二分更新\(f\)即可。时间复杂度\(O(nlog^{2}n)\)。

#include<cmath>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std; #define maxn 100010
int n; double f[maxn],rate[maxn],ak[maxn],bk[maxn];
struct NODE
{
double x,y;
friend inline bool operator <(const NODE &a,const NODE &b) { return a.x < b.x; }
friend inline double operator /(const NODE &a,const NODE &b) { return a.x*b.y-a.y*b.x; }
friend inline NODE operator -(const NODE &a,const NODE &b) { return (NODE){a.x-b.x,a.y-b.y}; }
inline double alpha() { return atan2(y,x); }
}ask[maxn],ham[maxn];
double bac[maxn]; inline int find(double key,int l,int r)
{
int mid;
while (l <= r)
{
mid = (l + r) >> 1;
if (bac[mid] > key) l = mid+1;
else r = mid - 1;
}
return l;
} inline void work(int l,int r)
{
if (l == r)
{
f[l] = max(f[l-1],f[l]);
ask[l].x = f[l]/(ak[l]*rate[l]+bk[l]);
ask[l].y = ask[l].x*rate[l];
return;
}
int mid = (l + r) >> 1;
work(l,mid);
sort(ask+l,ask+mid+1);
int m = 0;
for (int i = mid;i >= l;--i)
{
while (m > 1&&(ham[m]-ham[m-1])/(ask[i]-ham[m-1]) <= 0) --m;
ham[++m] = ask[i];
}
reverse(ham+1,ham+m+1);
for (int i = 1;i < m;++i) bac[i] = (ham[i+1]-ham[i]).alpha();
for (int i = mid+1;i <= r;++i)
{
double k = (NODE) {ak[i],-bk[i]}.alpha();
int pos = find(k,1,m-1);
f[i] = max(f[i],bk[i]*ham[pos].x+ak[i]*ham[pos].y);
}
work(mid+1,r);
} int main()
{
freopen("1492.in","r",stdin);
freopen("1492.out","w",stdout);
scanf("%d%lf",&n,&f[0]);
for (int i = 1;i <= n;++i)
scanf("%lf %lf %lf",ak+i,bk+i,rate+i);
work(1,n);
printf("%.3lf",f[n]);
fclose(stdin); fclose(stdout);
return 0;
}

BZOJ 1492 货币兑换的更多相关文章

  1. BZOJ 1492 货币兑换Cash

    http://www.lydsy.com/JudgeOnline/problem.php?id=1492 思路: 问题转变为维护一个凸包,每次转移都找凸包上的点,并更新凸壳 可以用splay维护,或者 ...

  2. BZOJ 1492 货币兑换 Cash CDQ分治

    这题n2算法就是一个维护上凸包的过程. 也可以用CDQ分治做. 我的CDQ分治做法和网上的不太一样,用左边的点建立一个凸包,右边的点在上面二分. 好处是思路清晰,避免了凸包的插入删除,坏处是多了一个l ...

  3. BZOJ 1492 货币兑换 cdq分治或平衡树维护凸包

    题意:链接 方法:cdq分治或平衡树维护凸包 解析: 这道题我拒绝写平衡树的题解,我仅仅想说splay不要写挂,insert边界条件不要忘.del点的时候不要脑抽d错.有想写平衡树的去看140142或 ...

  4. 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的数量. 然后就很明显了...平衡 ...

  5. NOI 2007 货币兑换Cash (bzoj 1492) - 斜率优化 - 动态规划 - CDQ分治

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

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

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1492   [题意] 有AB两种货币,每天可以可以付IPi元,买到A券和B券,且A:B= ...

  7. ●BZOJ 1492 [NOI2007]货币兑换Cash

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1492 题解: 斜率优化DP,CDQ分治 定义$DP[i]$为第i天结束后的最大收益. 由于题 ...

  8. BZOJ.1492.[NOI2007]货币兑换(DP 斜率优化 CDQ分治/Splay)

    BZOJ 洛谷 如果某天能够赚钱,那么一定会在这天把手上的金券全卖掉.同样如果某天要买,一定会把所有钱花光. 那么令\(f_i\)表示到第\(i\)天所拥有的最多钱数(此时手上没有任何金券),可以选择 ...

  9. 【BZOJ 1492】【NOI 2007】货币兑换Cash

    这是道CDQ分治的例题: $O(n^2)$的DP: f [1]←S* Rate[1] / (A[1] * Rate[1] + B[1]) Ans←SFor i ← 2 to n For j ←1 to ...

随机推荐

  1. HTML5 canvas标签绘制正三角形 鼠标按下点为中间点,鼠标抬起点为其中一个顶点

    用html5的canvas标签绘制圆.矩形比较容易,绘制三角形,坐标确定相当于前面两种难点,这里绘制的是正三角形,比较容易,我们只需要把鼠标刚按下去的点设置为三角形的中心点,鼠标抬起的点设置为三角形右 ...

  2. boost------asio库的使用1(Boost程序库完全开发指南)读书笔记

    asio库基于操作系统提供的异步机制,采用前摄器设计模式(Proactor)实现了可移植的异步(或者同步)IO操作,而且并不要求多线程和锁定,有效地避免了多线程编程带来的诸多有害副作用. 目前asio ...

  3. Android 仿PhotoShop调色板应用(三) 主体界面绘制

    版权声明:本文为博主原创文章,未经博主允许不得转载. Android 仿PhotoShop调色板应用(三) 主体界面绘制    关于PhotoShop调色板应用的实现我总结了两个最核心的部分:   1 ...

  4. unity3D与网页的交互

    由于项目需要,要求用unity来展示三维场景,并在三维中能够方便的查询数据库等.一开始尝试在unity中直接连接数据库,当时连的xml,然而每次发布成网页后都会出现路径找不到等问题,所以迫不得已采用了 ...

  5. iOS--inputView和inputAccessoryView

    iOS–inputView和inputAccessoryView 什么是inputView和inputAccessoryView? 如果是UITextField和UITextView,下面是声明文件源 ...

  6. javascript动画效果

    之前工作项目中,运用了缓动动画的效果,在网上看到其他大牛写的相关公式,结合工作需要,进行了整理,拿出来跟大家分享下,js代码中,只运用了一个小功能进行了测试 <!DOCTYPE html> ...

  7. 详解SQL Server 2005 Express下的事件探查器

    安装Visual Studio 2008会有附带的SQL Server 2005 Express版 我们开发一般都用那个都不单独安装SQL Server的 大家都知道express版的sql是没有 事 ...

  8. 使用Xcode插件,让iOS开发更加便捷

    在iOS开发过程中,写注释是一项必不可少的工作.这不仅有助于自己对代码整理回顾,而且提高了代码的可读性,让代码维护变得容易.但是,写注释又是一项枯燥的工作.我们浪费了大量的时间在输入/*,*,*/这样 ...

  9. OC - 29.自定义布局实现瀑布流

    概述 瀑布流是电商应用展示商品通常采用的一种方式,如图示例 瀑布流的实现方式,通常有以下几种 通过UITableView实现(不常用) 通过UIScrollView实现(工作量较大) 通过UIColl ...

  10. 一条sql语句循环插入N条不同记录(转)

    SET NOCOUNT ON IF (OBJECT_ID('TB' ) IS NOT NULL ) DROP TABLE TB GO CREATE TABLE TB(ID INT IDENTITY ( ...