Codeforces 1067D - Computer Game(矩阵快速幂+斜率优化)
好题。
首先显然我们如果在某一次游戏中升级,那么在接下来的游戏中我们一定会一直打 \(b_jp_j\) 最大的游戏 \(j\),因为这样得到的期望收益最大。
因此我们设 \(dp_i\) 表示还剩 \(i\) 秒并且当前没有升级过的最大收益。
那么有 \(dp_i=\max\limits_{j}\{dp_{i-1}(1-p_j)+X(i-1)p_j+p_ja_j\}\),其中 \(X=\max\{b_jp_j\}\)。
稍微解释一下上面的转移方程,我们枚举这一次选择玩哪个游戏,设为 \(j\),那么我们有 \(p_j\) 的概率获得胜利,之后每一轮期望会获得 \(X\) 的收益,得到的总收益就是 \(X(i-1)\),此外该轮还会获得 \(a_j\) 的收益,这种情况下的期望收益就是 \(X(i-1)p_j+p_ja_j\)。如果这次游戏没有取得胜利,那么问题转化为还剩 \(i-1\) 秒的情况,最大收益为 \(dp_{i-1}\),概率为 \(1-p_j\),期望收益为 \((1-p_j)dp_{i-1}\),把两者加起来可以得到 \(dp_{i-1}(1-p_j)+X(i-1)p_j+p_ja_j\)。对所有 \(j\) 取个 \(\max\) 即可得到上面的式子。
我们设 \(S_i=X(i-1)-dp_{i-1}\),那么上面的转移方程可以写成 \(dp_i=\max\{dp_{i-1}+p_jS_i+p_ja_j\}\)。注意到 \(S_j\) 是单调不减的,因为 \(S_{j+1}-S_{j}=(iX-dp_i)-(X(i-1)-dp_{i-1})=X-(dp_i-dp_{i-1})\),而 \(dp_i-dp_{i-1}\) 这个式子我们调用它的实际意义可知,它们的差距不可能大于一轮中的最大收益 \(X\),因此 \(X-(dp_i-dp_{i-1})\ge 0\)。
注意到上面改写过的 \(dp\) 方程可以视作,我们有若干个点 \((p_j,a_jp_j)\),你要对于所有点,过其做斜率为 \(-S_i\),取最大截距作为 \(dp_i\) 相较于 \(dp_{i-1}\) 的增量,看到这样的设问我们可以很自然地想到斜率优化。具体来说我们建出这 \(n\) 个点的上凸壳,那么最优切点肯定在上凸壳上,又因为 \(S_i\) 单调递增,因此最优切点的横坐标肯定不断向右移,因此我们可以均摊 \(\mathcal O(n+T)\) 地对于每一轮 DP 求出其最优切点。
如果这题 \(T\) 的数据范围比较小那么按照上文所述进行斜率优化即可通过,不过这丧心病狂的出题人偏偏将 \(T\) 数据范围加强到 \(10^{10}\)。这就导致直接一轮轮推过去的做法无法通过,不过注意到对于上凸壳上每个点,它作为最优转移点存在的时刻是一段区间,因此我们考虑从左到右遍历上凸壳上每一个点,二分它作为最优转移点的区间的右端点 \(t\),矩阵快速幂算出 \(t\) 时刻的 DP 值,并通过判断 \(S_t\) 的最优切点是否是该点来判断应当向左还是向右二分。具体来说,对于一段连续的且最优转移点均为 \(j\) 的 DP,它们的 DP 转移均可写成以下形式:
\begin{bmatrix}
1-p_j&0&0\\
p_jX&1&0\\
p_ja_j&1&1
\end{bmatrix}=
\begin{bmatrix}dp_{i+1}&i+1&1\end{bmatrix}
\]
矩阵快速幂即可。这样复杂度 \(n\log^2n\),再加上矩阵快速幂的大常数,有亿点点危,不过如果我们对于所有 \(k\in[0,\log_2(t)]\) 预处理出矩阵的 \(2^k\) 幂,然后倍增最优转移点区间的右端点,那么时间复杂度可以做到 \(n\log n\)。
const int MAXN=1e5;
const int LOG_T=36;
int sgn(ld x){return (x<-EPS)?-1:((x<EPS)?0:1);}
struct mat{
ld a[4][4];
mat(){for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) a[i][j]=0;}
mat operator *(const mat &rhs){
mat res;
for(int i=1;i<=3;i++) for(int j=1;j<=3;j++)
for(int k=1;k<=3;k++) res.a[i][k]+=a[i][j]*rhs.a[j][k];
return res;
}
} cur,pw[LOG_T+2];
int n,a[MAXN+5],b[MAXN+5];
ll t;ld p[MAXN+5],X=0;
struct point{
ld x,y;int id;
point(ld _x=0,ld _y=0,int _id=0):x(_x),y(_y),id(_id){}
bool operator <(const point &rhs) const{
if(sgn(x-rhs.x)) return sgn(x-rhs.x)<0;
return sgn(y-rhs.y)<0;
}
} P[MAXN+5];
int stk[MAXN+5],tp=0;
void calc_hull(){
sort(P+1,P+n+1);
for(int i=1,j;i<=n;i=j+1){
j=i;while(!sgn(P[i].x-P[j].x)) j++;j--;
while(tp>1&&(P[stk[tp]].y-P[stk[tp-1]].y)*(P[j].x-P[stk[tp]].x)<
(P[stk[tp]].x-P[stk[tp-1]].x)*(P[j].y-P[stk[tp]].y)) --tp;
stk[++tp]=j;
}
}
ld calc(point p,ld x){return p.x*x+p.y;}
int main(){
scanf("%d%lld",&n,&t);
for(int i=1;i<=n;i++){
scanf("%d%d%Lf",&a[i],&b[i],&p[i]);
P[i]=point(p[i],a[i]*p[i],i);chkmax(X,b[i]*p[i]);
}
calc_hull();
ll curp=0;cur.a[1][3]=1;
// for(int i=1;i<=tp;i++) printf("(%.10Lf %.10Lf)\n",P[stk[i]].x,P[stk[i]].y);
for(int i=1;;){
ld curS=X*curp-cur.a[1][1];
// printf("%lld %.10Lf\n",curp,curS);
while(i<tp&&(P[stk[i+1]].y-P[stk[i]].y)>=-curS*(P[stk[i+1]].x-P[stk[i]].x)) i++;
int id=P[stk[i]].id;
pw[0].a[1][1]=1-p[id];pw[0].a[1][2]=0;pw[0].a[1][3]=0;
pw[0].a[2][1]=p[id]*X;pw[0].a[2][2]=1;pw[0].a[2][3]=0;
pw[0].a[3][1]=p[id]*a[id];pw[0].a[3][2]=1;pw[0].a[3][3]=1;
for(int j=1;j<=LOG_T;j++) pw[j]=pw[j-1]*pw[j-1];
for(int j=LOG_T;~j;j--) if(curp+(1ll<<j)<t){
mat nw_mat=cur*pw[j];
ld nw=X*nw_mat.a[1][2]-nw_mat.a[1][1];
if((i==tp)||calc(P[stk[i]],nw)>calc(P[stk[i+1]],nw))
curp+=(1ll<<j),cur=cur*pw[j];
} cur=cur*pw[0];curp++;if(curp==t) break;
} printf("%.10Lf\n",cur.a[1][1]);
return 0;
}
Codeforces 1067D - Computer Game(矩阵快速幂+斜率优化)的更多相关文章
- Codeforces 691E题解 DP+矩阵快速幂
题面 传送门:http://codeforces.com/problemset/problem/691/E E. Xor-sequences time limit per test3 seconds ...
- CodeForces - 691E Xor-sequences 【矩阵快速幂】
题目链接 http://codeforces.com/problemset/problem/691/E 题意 给出一个长度为n的序列,从其中选择k个数 组成长度为k的序列,因为(k 有可能 > ...
- Codeforces 691E Xor-sequences(矩阵快速幂)
You are given n integers a1, a2, ..., an. A sequence of integers x1, x2, ..., xk is called a & ...
- Codeforces 954 dijsktra 离散化矩阵快速幂DP 前缀和二分check
A B C D 给你一个联通图 给定S,T 要求你加一条边使得ST的最短距离不会减少 问你有多少种方法 因为N<=1000 所以N^2枚举边数 迪杰斯特拉两次 求出Sdis 和 Tdis 如果d ...
- POJ 3150 Cellular Automaton --矩阵快速幂及优化
题意:给一个环,环上有n块,每块有个值,每一次操作是对每个点,他的值变为原来与他距离不超过d的位置的和,问k(10^7)次操作后每块的值. 解法:一看就要化为矩阵来做,矩阵很好建立,大白书P157页有 ...
- hdu 1575 Tr A(矩阵快速幂乘法优化算法)
Problem Description A为一个方阵,则Tr A表示A的迹(就是主对角线上各项的和),现要求Tr(A^k)%. Input 数据的第一行是一个T,表示有T组数据. 每组数据的第一行有n ...
- hihocoder第41周 骨牌覆盖(矩阵快速幂)
由于棋盘只有两行,所以如果第i列的骨牌竖着放,那么就转移为第1列到第i-1列骨牌有多少种摆法 如果第一行第i列骨牌横着放,那么第二行第i列也要横着放,那么就转移为了第1列到第i-2列骨牌有多少种方法 ...
- 【BZOJ1009】GT考试(KMP算法,矩阵快速幂,动态规划)
[BZOJ1009]GT考试(KMP算法,矩阵快速幂,动态规划) 题面 BZOJ 题解 看到这个题目 化简一下题意 长度为\(n\)的,由\(0-9\)组成的字符串中 不含串\(s\)的串的数量有几个 ...
- 2019.02.11 bzoj4818: [Sdoi2017]序列计数(矩阵快速幂优化dp)
传送门 题意简述:问有多少长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数,且其中至少有一个数是质数,答案对201704082017040820170408取模(n≤1e9, ...
随机推荐
- 3 Implementation: The Big Picture 实现:蓝图
三.Implementation: The Big Picture 实现:蓝图 3.1 Layering of a .NET Solution .Net解决方案的分层 The picture belo ...
- jq问题
<div id="box"> <p> <span>A</span> <span>B</span> </ ...
- Servlet学习一(Servlet的使用流程)
一.servlet运行流程 运行流程:浏览器发送请求到服务器,服务器根据url地址在webapps中寻找对应的项目文件夹然后再web.xml中检索对应的servlet,并进行调用二.servlet类写 ...
- 第四次Scrum Metting
日期:2021年4月29日 会议主要内容概述:交代近两日工作,进一步细化上次讨论细节,代码合并. 一.进度情况## 组员 负责 两日内已完成的工作 后两日计划完成的工作 工作中遇到的困难 徐宇龙 后端 ...
- [对对子队]会议记录4.14(Scrum Meeting 5)
今天已完成的工作 刘子航 工作内容:设计第2,3关 相关issue:设计关卡2,3 吴昭邦 工作内容:制作场景,暂时解决了坐标错位问题 相关issue:实现游戏场景中的必要模型 何瑞 ...
- camera HSYNC:VSYNC
HSYNC:行锁存,换行信号VSYNC:祯锁存,换页信号 320×240的屏,每一行需要输入320个脉冲来依次移位.锁存进一行的数据,然后来个HSYNC 脉冲换一行:这样依次输入240行之后换行同时来 ...
- P2774 方格取数问题(最小割)
P2774 方格取数问题 一看题目便知是网络流,但由于无法建图.... 题目直说禁止那些条件,这导致我们直接建图做不到,既然如此,我们这是就要逆向思维,他禁止那些边,我们就连那些边. 我们将棋盘染色, ...
- AGC036 A-Triangle | 构造
题目链接 题意: 给出一个数$S(1\leqslant S \leqslant 10^{18})$. 要求在平面直角坐标系中找到三个点$(X_1,Y_1),(X_2,Y_2),(X_3,Y_3)$,满 ...
- Spring Cloud Alibaba环境搭建
前言:Spring Cloud Alibaba是目前主流的分布式微服务架构,本文主要讲解了在IDEA中如何搭建Spring Cloud Alibaba环境,以及介绍Spring Cloud Aliba ...
- (一)FastDFS 高可用集群架构学习---简介
1.什么是FastDFS FastDFS 是余庆老师用c语言编写的一筐开源的分布式文件系统,充分考虑了冗余备份,负载均衡,线性扩容等机制,并注重高可用.高性能等指标,使用FastDFS可以很容易搭建一 ...