Codeforces Round #518 (Div. 1) Computer Game 倍增+矩阵快速幂
接近于死亡的选手没有水平更博客,所以现在每五个月更一篇。
这道题呢,首先如果已经有权限升级了,那么后面肯定全部选的是 \(p_ib_i\) 最高的。
设这个值为 \(M=\max \limits_i p_ib_i\)。
主要的问题在于前面怎么选。
假设剩下的时间还有 \(t\) 秒。那么我们很容易得到一个这样的式子。
\]
把 \(\max\)里面的内容整理一下。
\]
如果 \(i\) 确定了,那么 \(\max\) 里面的东西就是一个关于 \(tM-dp[t]\) 的一次函数。
而把一堆一次函数取 \(max\) 显然可以通过维护这些一次函数的凸包,然后在凸包上二分 \(tM-dp[t]\) 的位置解决。
但是这样做的时间复杂度为 \(O((n+t)\log n)\)。
可巧我们有一个显然的结论就是 \(dp[t+1]-dp[t] < M\)。
那么就是说 \(tM-dp[t] < (t+1)M -dp[t+1]\)。也就是说,需要在凸包上走的东西是单调递增的。
由于凸包不超过 \(n\) 段,所以可以在每一段上做矩阵快速幂。
1-p_i & p_iM & a_ip_i\\
0 & 1 & 1\\
0 & 0 & 1
\end{bmatrix}
\cdot
\begin{bmatrix}
dp[t]\\
t\\
1
\end{bmatrix}
=
\begin{bmatrix}
dp[t+1]\\
t+1\\
1
\end{bmatrix}
\]
直接二分是 \(O(n(\log n + \log^2t))\) 的。可以使用倍增,\(O(n(\log n+\log t))\)。
#include<bits/stdc++.h>
using namespace std;
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 1e5 + 7;
const int LOG = 36;
const double eps = 1e-13;
int n, nl;
ll t;
double M;
int a[N], b[N], q[N];
double p[N];
inline int dcmp(const double &x) { return fabs(x) < eps ? 0 : (x < 0 ? -1 : 1); }
struct Line {
double k, b;
inline bool operator < (const Line &a) const { return dcmp(k - a.k) < 0 || (dcmp(k - a.k) == 0 && b < a.b); }
// inline bool operator < (const Line &a) const { return b > a.b; }
} l[N];
inline double crs(const Line &l1, const Line &l2) { return (l2.b - l1.b) / (l1.k - l2.k); }
struct Matrix {
double a[3][3];
inline Matrix() { memset(a, 0, sizeof(a)); }
inline Matrix(const double &x) {
memset(a, 0, sizeof(a));
a[0][0] = a[1][1] = a[2][2] = x;
}
inline void print() {
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j)
dbg("%.13lf ", a[i][j]);
puts("");
}
}
inline Matrix operator * (const Matrix &b) {
Matrix c;
c.a[0][0] = a[0][0] * b.a[0][0] + a[0][1] * b.a[1][0] + a[0][2] * b.a[2][0];
c.a[0][1] = a[0][0] * b.a[0][1] + a[0][1] * b.a[1][1] + a[0][2] * b.a[2][1];
c.a[0][2] = a[0][0] * b.a[0][2] + a[0][1] * b.a[1][2] + a[0][2] * b.a[2][2];
c.a[1][0] = a[1][0] * b.a[0][0] + a[1][1] * b.a[1][0] + a[1][2] * b.a[2][0];
c.a[1][1] = a[1][0] * b.a[0][1] + a[1][1] * b.a[1][1] + a[1][2] * b.a[2][1];
c.a[1][2] = a[1][0] * b.a[0][2] + a[1][1] * b.a[1][2] + a[1][2] * b.a[2][2];
c.a[2][0] = a[2][0] * b.a[0][0] + a[2][1] * b.a[1][0] + a[2][2] * b.a[2][0];
c.a[2][1] = a[2][0] * b.a[0][1] + a[2][1] * b.a[1][1] + a[2][2] * b.a[2][1];
c.a[2][2] = a[2][0] * b.a[0][2] + a[2][1] * b.a[1][2] + a[2][2] * b.a[2][2];
return c;
}
} f[LOG];
inline void ycl() {
for (int i = 1; i <= n; ++i) smax(M, p[i] * b[i]), l[i] = (Line){ p[i], p[i] * a[i] };
sort(l + 1, l + n + 1);
for (int i = 1; i <= n; ++i) if (dcmp(l[i].k - l[nl].k)) l[++nl] = l[i]; else l[nl] = l[i];
n = nl, nl = 1;
q[1] = 1;
for (int i = 2; i <= n; ++i) {
// if (dcmp(crs(l[q[nl]], l[i])) <= 0) continue;
while (nl > 1 && dcmp(crs(l[q[nl - 1]], l[i]) - crs(l[q[nl - 1]], l[q[nl]])) <= 0) --nl;
q[++nl] = i;
}
for (int i = 1; i <= nl; ++i) l[i] = l[q[i]];//, dbg("Line : %.13lf %.13lf\n", l[i].k, l[i].b);
n = nl;
// for (int i = 1; i <= n; ++i) dbg("Line : %.13lf %.13lf\n", l[i].k, l[i].b);
// dbg("%.13lf %.13lf\n", crs(l[1], l[4]), crs(l[1], l[3]));
}
inline void work() {
ycl();
double dp = 0;
ll tt = 0;
for (int i = 1; i <= n && tt < t; ++i) {
double stp;
if (i < n) stp = crs(l[i], l[i + 1]);
else stp = 1e20;
if (tt < t && dcmp(tt * M - dp - stp) >= 0) continue;
Matrix A, B;
A.a[0][0] = dp, A.a[1][0] = tt, A.a[2][0] = 1;
B.a[0][0] = 1 - l[i].k, B.a[0][1] = l[i].k * M, B.a[0][2] = l[i].b;
B.a[1][1] = 1, B.a[1][2] = 1;
B.a[2][2] = 1;
f[0] = B;
for (int i = 1; i < LOG; ++i) f[i] = f[i - 1] * f[i - 1];
for (int i = LOG - 1; ~i; --i) if (tt + (1ll << i) < t) {
Matrix C = f[i] * A;
// if (i == 1) C.print();
if (dcmp(C.a[1][0] * M - C.a[0][0] - stp) < 0) A = C, tt += 1ll << i;
}
A = f[0] * A, ++tt;
dp = A.a[0][0];
}
printf("%.13lf\n", dp);
}
inline void init() {
read(n), read(t);
for (int i = 1; i <= n; ++i) read(a[i]), read(b[i]), scanf("%lf", &p[i]);
}
int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
Codeforces Round #518 (Div. 1) Computer Game 倍增+矩阵快速幂的更多相关文章
- Codeforces Round #324 (Div. 2) B. Kolya and Tanya 快速幂
B. Kolya and Tanya Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/584/pro ...
- Codeforces Round #362(Div1) D Legen...(AC自动机+矩阵快速幂)
题目大意: 给定一些开心串,每个串有一个开心值,构造一个串,每包含一次开心串就会获得一个开心值,求最大获得多少开心值. 题解: 首先先建立AC自动机.(建立fail指针的时候,对val要进行累加) 然 ...
- Educational Codeforces Round 13——D. Iterated Linear Function(矩阵快速幂或普通快速幂水题)
D. Iterated Linear Function time limit per test 1 second memory limit per test 256 megabytes input ...
- Codeforces Round #518 (Div. 2) [Thanks, Mail.Ru!]
Codeforces Round #518 (Div. 2) [Thanks, Mail.Ru!] https://codeforces.com/contest/1068 A #include< ...
- Codeforces 1067D - Computer Game(矩阵快速幂+斜率优化)
Codeforces 题面传送门 & 洛谷题面传送门 好题. 首先显然我们如果在某一次游戏中升级,那么在接下来的游戏中我们一定会一直打 \(b_jp_j\) 最大的游戏 \(j\),因为这样得 ...
- 2018.11.08 NOIP模拟 景点(倍增+矩阵快速幂优化dp)
传送门 首先按照题意构造出转移矩阵. 然后可以矩阵快速幂求出答案. 但是直接做是O(n3qlogm)O(n^3qlogm)O(n3qlogm)的会TTT掉. 观察要求的东西发现我们只关系一行的答案. ...
- Codeforces Round #518 (Div. 2) B. LCM gcd+唯一分解定律
题意:给出b 求lcm(a,b)/a 在b从1-1e18有多少个不同得结果 思路lcm*gcd=a*b 转换成 b/gcd(a,b) 也就是看gcd(a,b)有多少个值 可以把b 由唯一分解 ...
- Codeforces Round #518 (Div. 2) B LCM
传送门 https://www.cnblogs.com/violet-acmer/p/10163375.html 题解: 这道题有点意思,有点数学的味道. 根据定义“[a,b] / a”可得这求得是l ...
- Codeforces Round #518 Div. 1没翻车记
A:设f[i][j][0/1]为前i个数第i位为j且第i位未满足/已满足限制的方案数.大力dp前缀和优化即可. #include<iostream> #include<cstdio& ...
随机推荐
- 深圳市利汇电子商务科技有限公司2019年java面试笔试题
垃圾公司,建议不要去,写的地址去了发现是两个公司公用一个办公场地,还没有公司的招牌,去了交简历给前台然后就是 填一份求职申请,一份笔试题如下,然后就等待,先是人事的一个小妹妹面试,问一些个人问题,为什 ...
- Python_010(迭代器)
一.函数名的运用 1.函数名的内存地址 def func(): print("英雄联盟") print(func) #输出结果: <function func at 0x00 ...
- 图论 List
题目 #A 小 K 的农场 (Unaccepted) #B 信息传递 (Unaccepted) #C 最短路计数 (Accepted) #D 通往奥格瑞玛的道路 (Accepted) ...
- [CSP-S模拟测试]:Permutation(线段树+拓扑排序+贪心)
题目描述 你有一个长度为$n$的排列$P$与一个正整数$K$你可以进行如下操作若干次使得排列的字典序尽量小对于两个满足$|i−j|\geqslant K$且$|P_i−P_j|=1$的下标$i$与$j ...
- 浅析java中的string
在学习java36讲的时候看到评论区有人提出的一个问题: String s1 = new String("do"); s1.intern(); String s2 = " ...
- 阿里云服务器 Ubuntu 安装 LNMP
1.设定实例化服务器IP密码. 2.设定安全组件端口 80 和 3306 系统默认提供端口 22. //阿里云需要设定安全组件端口必须设定. 3.安装一键lnmp系统. 教程地址 https://ln ...
- 【进阶技术】一篇文章搞掂:Spring Cloud Stream
本文总结自官方文档http://cloud.spring.io/spring-cloud-static/spring-cloud-stream/2.1.0.RC3/single/spring-clou ...
- 2018 CCPC 吉林站 H Lovers || HDU 6562 (线段树哦)
http://acm.hdu.edu.cn/showproblem.php?pid=6562 题意: q次操作 1.将第l~r个数的左边和和右边都加上一个数d, 使得这个数变成 dsiddsid的形式 ...
- JS-立即执行函数表达式(IIFE)
javascript 函数调用 在 javascript 中,每一个函数在被调用的时候都会创建一个执行上下文,在该函数内部定义的变量和函数只能在该函数内部被使用,而正是因为这个上下文,使得我们在调用函 ...
- Mybatis 批量插入和更新小例
SpringBoot配置Mybatis前文有博文,数据库mysql: package com.example.demo.biz.dto; public class User { private int ...