题意

题目链接

Sol

解题的关键是看到题目里的提示。。。

设\(f[i]\)表示到第\(i\)天所持有软妹币的最大数量,显然答案为\(max_{i = 1}^n f[i]\)

转移为\(f_i = max(f_{i - 1}, A_i \frac{f_j R_j}{A_j R_j + B_j} + B_i \frac{f_j}{A_j R_j + B_j})\)

变形一下:

\[\frac{f_i}{B_i} - \frac{f_j}{A_j R_j + B_j} = \frac{A_i}{B_i} \frac{f_j R_j}{A_j R_j + B_j}
\]

设\(y_i = \frac{f_j}{A_j R_j + B_j}, x_i = \frac{f_j R_j}{A_j R_j + B_j}\)

显然可以斜率优化,也就是拿一条斜率为\(-\frac{A_i}{B_i}\)的直线从上往下切。

但是这里的斜率和\(x\)都是不单调的。

按照老祖宗说的

\(x\)不单调cdq

斜率不单调二分凸包

然后xjb写一写就好了。我写的cdq复杂度是\(O(nlog^2n)\)的,每次暴力建左侧的凸包,然后在右边二分,虽然很好写,但是在BZOJ上成功T飞。。

看了下SovietPower大佬的博客发现有nlogn的做法Orz,就是先按斜率排序,然后转移的时候把下标分为\(<mid\)和\(>= mid\)的,直接用类似双指针的东西扫就行了

#include<bits/stdc++.h>
#define Pair pair<double, double>
#define MP(x, y) make_pair(x, y)
#define fi first
#define se second
//#define int long long
#define LL long long
#define db double
#define Fin(x) {freopen(#x".in","r",stdin);}
#define Fout(x) {freopen(#x".out","w",stdout);}
using namespace std;
const int MAXN = 1e6 + 10, mod = 1e9 + 7, INF = 1e9 + 10;
const double eps = 1e-9;
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;}
template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;}
template <typename A> inline void debug(A a){cout << a << '\n';}
template <typename A> inline LL sqr(A x){return 1ll * x * x;}
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, S;
struct Sta {
int id;
db A, B, R, x, y, f;
void Get() {
x = f * R / (A * R + B);
y = f / (A * R + B);
}
bool operator < (const Sta &rhs) const {
return f < rhs.f;
}
}a[MAXN], st[MAXN];
vector<Pair> v;
double GetK(Pair a, Pair b) {
if((b.fi - a.fi) < eps) return INF;
return (b.se - a.se) / (b.fi - a.fi);
}
void GetConvexHull(int l, int r) {
v.clear();
for(int i = l; i <= r; i++) {
double x = a[i].x, y = a[i].y;
while(v.size() > 1 && ((GetK(v[v.size() - 1], MP(x, y)) > GetK(v[v.size() - 2], v[v.size() - 1])) )) v.pop_back();
v.push_back(MP(x, y));
}
}
int cnt = 0;
db Find(int id, db k) {
int l = 0, r = v.size() - 1, ans = 0;
while(l <= r) {
int mid = l + r >> 1;
if((mid == 0) || (GetK(v[mid - 1], v[mid]) > k)) l = mid + 1, ans = mid;
else r = mid - 1;
}
return a[id].A * v[ans].fi + a[id].B * v[ans].se;
}
db CDQ(int l, int r) {
if(l == r) {
int i = l;
chmax(a[i].f, a[i - 1].f);
chmax(a[i].f, a[i].f * ((a[i].A * a[i].R + a[i].B) / (a[i].A * a[i].R + a[i].B)));
a[l].Get();
return a[i].f;
}
int mid = l + r >> 1;
db lmx = CDQ(l, mid);
GetConvexHull(l, mid);
for(int i = mid + 1; i <= r; i++) chmax(a[i].f, max(lmx, Find(i, -a[i].A / a[i].B)));
CDQ(mid + 1, r);
int tl = l, tr = mid + 1, tot = tl - 1;
while(tl <= mid || tr <= r) {
if((tr > r) || (tl <= mid && a[tl].x < a[tr].x)) st[++tot] = a[tl++];//这里要加上tl <= mid
else st[++tot] = a[tr++];
}
db rt = 0;
for(int i = l; i <= r; i++) a[i] = st[i], chmax(rt, a[i].f);
return rt;
}
signed main() {
// freopen("a.in", "r", stdin);
N = read(); S = read();
for(int i = 1; i <= N; i++) scanf("%lf %lf %lf", &a[i].A, &a[i].B, &a[i].R), a[i].id = i;
a[0].f = S;
CDQ(1, N);
db ans = 0;
for(int i = 1; i <= N; i++) chmax(ans, a[i].f);
printf("%.3lf", ans);
return 0;
}

洛谷P4027 [NOI2007]货币兑换(dp 斜率优化 cdq 二分)的更多相关文章

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

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

  2. P4027 [NOI2007]货币兑换(斜率优化dp+cdq分治)

    P4027 [NOI2007]货币兑换 显然,如果某一天要买券,一定是把钱全部花掉.否则不是最优(攒着干啥) 我们设$f[j]$为第$j$天时用户手上最多有多少钱 设$w$为花完钱买到的$B$券数 $ ...

  3. 洛谷P4027 [NOI2007]货币兑换

    P4027 [NOI2007]货币兑换 算法:dp+斜率优化 题面十分冗长,题意大概是有一种金券每天价值会有变化,你可以在某些时间点买入或卖出所有的金券,问最大收益 根据题意,很容易列出朴素的状态转移 ...

  4. 洛谷 P4027 [NOI2007]货币兑换 解题报告

    P4027 [NOI2007]货币兑换 题目描述 小 \(Y\) 最近在一家金券交易所工作.该金券交易所只发行交易两种金券:\(A\) 纪念券(以下简称 \(A\) 券)和 \(B\) 纪念券(以下简 ...

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

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

  6. [NOI2007]货币兑换 --- DP + 斜率优化(CDQ分治)

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

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

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

  8. 【BZOJ1492】[NOI2007]货币兑换Cash 斜率优化+cdq分治

    [BZOJ10492][NOI2007]货币兑换Cash Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下简称B券).每 ...

  9. [BZOJ1492] [NOI2007]货币兑换Cash 斜率优化+cdq/平衡树维护凸包

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

随机推荐

  1. [Python]字典Dictionary、列表List、元组Tuple差异化理解

    概述:Python中这三种形式的定义相近,易于混淆,应注意区分. aDict={'a':1, 'b':2, 'c':3, 'd':4, 'e':5} aList=[1,2,3,4,5] aTuple= ...

  2. java.util包详解

    介绍Java的实用工具类库java.util包.在这个包中,Java提供了一些实用的方法和数据结构.本章介绍Java的实用工具类库java.util包.在这个包中,Java提供了一些实用的方法和数据结 ...

  3. iOS多线程---GCD中线程的通信

    在子线程的任务完成后,有时候需要从子线程回到主线程,刷新UI. 从子线程中回到主线程,以前已经写过一种方法: [self.imageView performSelectorOnMainThread:@ ...

  4. 移动端 实现ul横向滚动条

    ul { display: flex; width: 100%; height: 3.333333rem; background: #fff; padding: 0.373333rem 0.32rem ...

  5. linux安装git,linux安装jenkins

    首先是两个地址,分别是git的版本下载地址,jenkins的下载地址 https://mirrors.edge.kernel.org/pub/software/scm/git/ http://mirr ...

  6. php内核为变量的值分配内存的几个宏

    在php5.3之前,为某变量分配内存是用宏 MAKE_STD_ZVAL; 737 #define MAKE_STD_ZVAL(zv) \ # /Zend/zend.h738 ALLOC_ZVAL(zv ...

  7. POJ 2393

    #include <iostream> #include <algorithm> using namespace std; int main() { //freopen(&qu ...

  8. LruCache源码分析

    LRU(Least Recently Used)是一种很常用的资源调度策略,与20/80原则契合,在资源达到上限时倾向保留最近经常访问的资源对象. Android中基于LRU实现了缓存对象,即LruC ...

  9. python中如何打印某月日历

    Calendar模块有很广泛的方法用来处理年历和月历,例如打印某月的月历: import calendar cal = calendar.month(2017, 10) print ("以下 ...

  10. Redis-cli命令总结

    连接操作相关的命令 默认直接连接  远程连接-h 192.168.1.20 -p 6379 ping:测试连接是否存活如果正常会返回pong echo:打印 select:切换到指定的数据库,数据库索 ...