洛谷P4027 [NOI2007]货币兑换(dp 斜率优化 cdq 二分)
题意
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})\)
变形一下:
\]
设\(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 二分)的更多相关文章
- BZOJ.1492.[NOI2007]货币兑换(DP 斜率优化 CDQ分治/Splay)
BZOJ 洛谷 如果某天能够赚钱,那么一定会在这天把手上的金券全卖掉.同样如果某天要买,一定会把所有钱花光. 那么令\(f_i\)表示到第\(i\)天所拥有的最多钱数(此时手上没有任何金券),可以选择 ...
- P4027 [NOI2007]货币兑换(斜率优化dp+cdq分治)
P4027 [NOI2007]货币兑换 显然,如果某一天要买券,一定是把钱全部花掉.否则不是最优(攒着干啥) 我们设$f[j]$为第$j$天时用户手上最多有多少钱 设$w$为花完钱买到的$B$券数 $ ...
- 洛谷P4027 [NOI2007]货币兑换
P4027 [NOI2007]货币兑换 算法:dp+斜率优化 题面十分冗长,题意大概是有一种金券每天价值会有变化,你可以在某些时间点买入或卖出所有的金券,问最大收益 根据题意,很容易列出朴素的状态转移 ...
- 洛谷 P4027 [NOI2007]货币兑换 解题报告
P4027 [NOI2007]货币兑换 题目描述 小 \(Y\) 最近在一家金券交易所工作.该金券交易所只发行交易两种金券:\(A\) 纪念券(以下简称 \(A\) 券)和 \(B\) 纪念券(以下简 ...
- LOJ 2353 & 洛谷 P4027 [NOI2007]货币兑换(CDQ 分治维护斜率优化)
题目传送门 纪念一下第一道(?)自己 yy 出来的 NOI 题. 考虑 dp,\(dp[i]\) 表示到第 \(i\) 天最多有多少钱. 那么有 \(dp[i]=\max\{\max\limits_{ ...
- [NOI2007]货币兑换 --- DP + 斜率优化(CDQ分治)
[NOI2007]货币兑换 题目描述: 小 Y 最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A 纪念券(以下简称 A 券)和 B 纪念券(以下简称 B 券). 每个持有金券的顾客都有一个 ...
- [BZOJ1492][NOI2007]货币兑换Cash(斜率优化+CDQ分治)
1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 5838 Solved: 2345[Submit][Sta ...
- 【BZOJ1492】[NOI2007]货币兑换Cash 斜率优化+cdq分治
[BZOJ10492][NOI2007]货币兑换Cash Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下简称B券).每 ...
- [BZOJ1492] [NOI2007]货币兑换Cash 斜率优化+cdq/平衡树维护凸包
1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 5907 Solved: 2377[Submit][Sta ...
随机推荐
- 解决ie9以下浏览器对html5新增标签的不识别,并导致CSS不起作用的问题
https://www.cnblogs.com/yangjie-space/p/4816279.html html5shiv.js和respond.min.js 做页面常用的东西,写这里用的时候省点去 ...
- 关于rpm的命令
我是从这里学的:https://www.cnblogs.com/picaso/archive/2012/07/02/2573748.html 软件的安装时操作系统管理的基础,与Windows不同,Li ...
- Redis初探,写个HelloWorld
资源获取 https://redis.io/download 从官网上下载redis的源码,使用gcc的安装方式. 安装 make make install 需要达到的效果是,在/usr/local/ ...
- crop和resize操作区别
crop:对图像进行剪切 resize:对图像进行伸缩 实践代码 import cv2 bb2d = [30, 30, 72 ,42] image = cv2.imread('car.png') pt ...
- (转)在 WebSphere Application Server 中修改主机名称并迁移概要文件
原文:https://www.ibm.com/developerworks/cn/websphere/techjournal/0905_webcon/0905_webcon.html 修改主机名 让我 ...
- java c :foreach 标签怎么获取自增分页序号
问题描述: 如果每页10条,下一页就从11递增,依次类推:用varStatus,下一页又从1开始了 解决方案: <c:forEach var="pag" begin=&quo ...
- javascript闭包使用 分类: JavaScript 2015-05-01 11:34 652人阅读 评论(3) 收藏
之前看到一段代码,很是不能理解,然后就查找资料并且找网络上得大牛请教,最后弄懂了这段代码,然后就拿出来总结一下. 1.挖坑 先来看一段代码: var arrTest = []; for (var i ...
- Python -- Gui编程 -- Tkinter的使用 -- 对话框消息框
1.消息框 tkMessageBox.py import tkinter from tkinter import messagebox def cmd(): global n global butto ...
- centos 关闭selinux 临时关闭selinux 报错 setenforce: setenforce() failed
关闭selinux的方法有两种:临时关闭和永久关闭. 查看selinux的状态:estatus [root@--- ~]# sestatus SELinux status: enabled SELin ...
- 8-lvs-负载均衡
注意: linux集群的时间需要一致 并发量在千万以上, 一般才会使用此种方式, 基于第四层进行ip欺骗, 使得nginx只接受上行流量, 下行流量通过具体执行的服务器直接返回 由章文嵩博士(淘宝) ...