CF1067D. Computer Game(斜率优化+倍增+矩阵乘法)
题目链接
https://codeforces.com/contest/1067/problem/D
题解
首先,如果我们获得了一次升级机会,我们一定希望升级 \(b_i \times p_i\) 最大的任务,并且之后只完成该任务,这样才能使得期望收益最大。换句话说,当我们完成成功了一次任务之后,决策就固定了。因此,我们实际需要考虑的是还未完成任何任务时的决策。
为了方便,我们记 \(\max\limits_{1 \leq i \leq n}\{b_ip_i\}\) 为 \(m\)。
我们设 \(f_t\) 表示还未完成任何任务且还剩 \(t\) 秒时使用最优决策得到的期望收益。如果我们选择在这一秒完成任务 \(i\),那么期望收益即为:\(p_i \times ((t - 1)m + a_i) + (1 - p_i)f_{t - 1}\)。因此,转移即为:
\]
直接用该转移式做 dp 的时间复杂度是 \(O(tn)\) 的。我们再将转移式变形:\(-((t - 1)m - f_{t - 1})p_i + f_t - f_{t - 1} = p_ia_i\),该式子显然可以使用斜率优化,将 \((t - 1)m - f_{t - 1}\) 看做斜率 \(k\),那么所求即为斜率为 \(k\) 且经过点 \((-p_i, p_ia_i)\) 的直线在 \(y\) 轴上的最大的截距。我们预处理出所有 \(n\) 个点 \((-p_i, p_ia_i)\) 构成的上凸包后,每次在凸包上二分找最优点即可。这样,我们得到了一个时间复杂度为 \(O(t \log n)\) 的较为优秀的做法。不过本题中的 \(t \leq 10^{10}\),因此这样的做法依然无法通过。
不过幸运的是,在本题中,随着 \(t\) 的增加,斜率 \(k\)(即 \((t - 1)m - f_{t - 1}\))是单调不下降的。
首先证明上述结论。对于任意的 \(t > 0\),我们希望证明 \(tm - f_t \geq (t - 1)m - f_{t - 1}\)。将式子变形,即为 \(f_{t} - f_{t - 1} \leq m\)。考虑该不等式的实际意义,显然 \(f_{t - 1}\) 与 \(f_t\) 的差不会超过 \(m\),因为我们无法在 \(1\) 秒内得到大于 \(m\) 的收益。因此,结论是成立的。
该结论告诉我们了一个重要信息:凸包上的每个点所影响的 \(f\) 的下标 \(t\) 一定是一段连续的区间。由于凸包由不超过 \(n\) 个点构成,因此我们可以依次求出每一个点所对应的 \(f\) 的下标的范围。分析 \(f\) 的转移式子:\(f_t = \max\limits_{1 \leq i \leq n}\{p_i((t - 1)m - f_{t - 1}) + p_ia_i\} + f_{t - 1}\),当 \(p_i, a_i\) 一定时,该转移是可以使用矩阵乘法优化的,因此对于每一个点,我们可以预处理出在该点上的 \(2^k\) 次转移对应的矩阵,然后倍增求出该点对应的 \(f\) 下标的范围边界。这样,本题就在 \(O(n\omega^3 \log t)\) 的时间内得到了解决,其中 \(\omega\) 是矩阵的大小。
(在下面的代码实现中 \(\omega = 4\)(矩阵构造详见代码),但存在转移矩阵的大小为 \(3 \times 3\) 的做法)
代码
#include<bits/stdc++.h>
using namespace std;
#define rg register
typedef long long ll;
template<typename T> inline bool checkMax(T& a, const T& b) {
return a < b ? a = b, true : false;
}
const int N = 1e5 + 10;
const double eps = 1e-12;
int n, a[N], b[N], top;
ll times;
double p[N], m;
struct Point {
double x, y;
Point () {}
Point (double x, double y): x(x), y(y) {}
bool operator < (const Point& a) const {
return x == a.x ? y < a.y : x < a.x;
}
} points[N], _stack[N];
inline double slope(Point a, Point b) {
return fabs(a.x - b.x) < eps ? 1e100 : (b.y - a.y) / (b.x - a.x);
}
struct Matrix {
double a[4][4];
Matrix () {
memset(a, 0, sizeof a);
}
Matrix operator * (const Matrix& b) const {
Matrix res;
for (rg int i = 0; i < 4; ++i) {
for (rg int j = 0; j < 4; ++j) {
for (rg int k = 0; k < 4; ++k) {
res.a[i][j] += a[i][k] * b.a[k][j];
}
}
}
return res;
}
} mat, trans[40];
int main() {
scanf("%d%I64d", &n, ×);
for (rg int i = 1; i <= n; ++i) {
scanf("%d%d%lf", &a[i], &b[i], &p[i]);
points[i] = Point (-p[i], a[i] * p[i]);
checkMax(m, p[i] * b[i]);
}
sort(points + 1, points + 1 + n);
_stack[top = 1] = points[1];
for (rg int i = 2; i <= n; ++i) {
for (; top > 1 && slope(_stack[top], points[i]) >= slope(_stack[top - 1], _stack[top]); --top);
_stack[++top] = points[i];
}
ll now = 0;
trans[0].a[1][0] = 1;
trans[0].a[1][1] = 1;
trans[0].a[2][0] = 1;
trans[0].a[2][2] = 1;
trans[0].a[3][2] = 1;
trans[0].a[3][3] = 1;
for (rg int i = top; i && now ^ times; --i) {
double r = i == 1 ? 1e100 : slope(_stack[i - 1], _stack[i]);
double x = -_stack[i].x, y = _stack[i].y;
mat.a[0][1] = y;
mat.a[0][2] = now * x * m;
mat.a[0][3] = x * m;
trans[0].a[0][0] = 1 - x;
if (now * m - mat.a[0][0] > r) {
continue;
}
for (rg int j = 1; j < 34; ++j) {
trans[j] = trans[j - 1] * trans[j - 1];
}
for (rg int j = 33; ~j; --j) {
if (now + (1ll << j) >= times) {
continue;
}
Matrix old = mat;
mat = mat * trans[j];
double k = (now + (1ll << j)) * m - mat.a[0][0];
if (k >= r) {
mat = old;
continue;
}
now += 1ll << j;
}
++now;
mat = mat * trans[0];
}
printf("%.15lf\n", mat.a[0][0]);
return 0;
}
CF1067D. Computer Game(斜率优化+倍增+矩阵乘法)的更多相关文章
- [CF1067D]Computer Game[凸包/斜率优化+倍增+矩阵乘法]
题意 你有 \(n\) 个任务,初始收益为 \(a\) ,共 \(t\) 轮游戏,每轮可以选择完成一个任务(可以做多次),完成之后可以给任意任务升级,升级之后的任务收益为 \(b\) ,每个任务还有完 ...
- CF781D Axel and Marston in Bitland [倍增 矩阵乘法 bitset]
Axel and Marston in Bitland 好开心第一次补$F$题虽然是$Div.2$ 题意: 一个有向图,每条边是$0$或$1$,要求按如下规则构造一个序列然后走: 第一个是$0$,每次 ...
- 【loj2325】「清华集训 2017」小Y和恐怖的奴隶主 概率dp+倍增+矩阵乘法
题目描述 你有一个m点生命值的奴隶主,奴隶主受伤未死且当前随从数目不超过k则再召唤一个m点生命值的奴隶主. T次询问,每次询问如果如果对面下出一个n点攻击力的克苏恩,你的英雄期望会受到到多少伤害. 输 ...
- 倍增&矩阵乘法 专题复习
倍增&矩阵乘法 专题复习 PreWords 这两个基础算法我就不多说啦,但是还是要介绍一下" 广义矩阵 "乘法 其实就是把矩阵换成取\(max\),然后都一样... 据神仙 ...
- 4.28 省选模拟赛 负环 倍增 矩阵乘法 dp
容易想到 这个环一定是简单环. 考虑如果是复杂环 那么显然对于其中的第一个简单环来说 要么其权值为负 如果为正没必要走一圈 走一部分即可. 对于前者 显然可以找到更小的 对于第二部分是递归定义的. 综 ...
- Codeforces 576D - Flights for Regular Customers(bitset 优化广义矩阵乘法)
题面传送门 题意: 有一张 \(n\) 个点 \(m\) 条边的有向图,你初始在 \(1\) 号点,边上有边权 \(c_i\) 表示只有当你经过至少 \(c_i\) 条边的时候你才能经过第 \(i\) ...
- 【POJ3613】Cow Relays 离散化+倍增+矩阵乘法
题目大意:给定一个 N 个顶点,M 条边的无向图,求从起点到终点恰好经过 K 个点的最短路. 题解:设 \(d[1][i][j]\) 表示恰好经过一条边 i,j 两点的最短路,那么有 \(d[r+m] ...
- Codeforces 1067D - Computer Game(矩阵快速幂+斜率优化)
Codeforces 题面传送门 & 洛谷题面传送门 好题. 首先显然我们如果在某一次游戏中升级,那么在接下来的游戏中我们一定会一直打 \(b_jp_j\) 最大的游戏 \(j\),因为这样得 ...
- poj3613:Cow Relays(倍增优化+矩阵乘法floyd+快速幂)
Cow Relays Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7825 Accepted: 3068 Descri ...
随机推荐
- Linux ls命令详解-乾颐堂CCIE
ls命令用法举例: 例一:列出/home文件夹下的所有文件和目录的详细资料: 1 ls -l -R /home 命令参数之前要有一短横线“-”, 上面的命令也可以这样写: 1 ls -lR /ho ...
- PXE
PXE 摘自:http://www.360doc.com/content/15/0226/08/17652659_450872586.shtml 一.简介 1.1 什么是PXE PXE(Pre ...
- JSON Web Token(JWT)学习笔记
1.JWT 的Token 标准的Token由三个部分并以.(点号)连接方式组成,即 header.payload.signature,如下 eyJhbGciOiJIUzI1NiIsInR5cCI6Ik ...
- redis 缓存用户账单策略
最近项目要求分页展示用户账单列表,为提高响应使用redis做缓存,用到的缓存策略和大家分享一下. 需求描述:展示用户账单基本信息以时间倒序排序,筛选条件账单类型(所有,订单收入.提现.充值...). ...
- HDU 6069 Counting Divisors (素数+筛法)
题意:给定 l,r,k,让你求,其中 l <= r <= 1e12, r-l <= 1e6, k <= 1e7. 析:首先这个题肯定不能暴力,但是给定的区间较小,可以考虑筛选, ...
- Redis实现高并发下的抢购、秒杀功能
博主最近在项目中遇到了抢购问题!现在分享下.抢购.秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个:1 高并发对数据库产生的压力2 竞争状态下如何解决库存的正确减少("超卖" ...
- python 函数星号参数说明
转自: python 函数参数的传递(参数带星号的说明) python中函数参数的传递是通过赋值来传递的.函数参数的使用又有俩个方面值得注意:1.函数参数是如何定义的 2.在调用函数的过程中参数是如何 ...
- A Multi-Sensorial Simultaneous Localization and Mapping (SLAM) System for Low-Cost Micro Aerial Vehicles in GPS-Denied Environments
A Multi-Sensorial Simultaneous Localization and Mapping (SLAM) System for Low-Cost Micro Aerial Vehi ...
- 关于Javascript 那些事
Javascript是一种由Netscape的LiveScript发展而来的原型化继承的面向对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如Perl,遗留的速度问题,为 ...
- CSS中的三种基本的定位机制(普通流、定位、浮动)
一.普通流 普通流中元素框的位置由元素在XHTML中的位置决定.块级元素从上到下依次排列,框之间的垂直距离由框的垂直margin计算得到.行内元素在一行中水平布置. 普通流就是html文档中的元素如块 ...