Codeforces Round #370 (Div. 2)E. Memory and Casinos[期望概率+线段树区间合并]详细推导
题目链接
题目大意:就说一个赌徒在nnn个赌场里面转,在每个赌场他有pip_ipi的胜率,如果赢了就向右走,输了就向左走,如果到达000或者n+1n+1n+1号赌场就相当退出的了赌局。定义统治区间[l,r][l,r][l,r],就是在第lll个赌场不能输,并且在某次赌博中在赌场rrr获得胜利结束赌博。
现在有两种操作:1.修改一个赌场的胜率
2.询问统治[l,r][l,r][l,r]的概率是多少
解题思路:设f[i]f[i]f[i]表示从位置i走到r+1并且没有走出区间[l,r]位置i走到r+1并且没有走出区间[l,r]位置i走到r+1并且没有走出区间[l,r]的概率,那么1.f[i]=f[i+1]∗p[i]+f[i−1]∗(1−p[i])1.f[i]=f[i+1]*p[i]+f[i-1]*(1-p[i])1.f[i]=f[i+1]∗p[i]+f[i−1]∗(1−p[i])
2.整理得f[i]−f[i−1]=(f[i+1]−f[i−1])∗p[i]2.整理得f[i]-f[i-1]=(f[i+1]-f[i-1])*p[i]2.整理得f[i]−f[i−1]=(f[i+1]−f[i−1])∗p[i]这里i+1和i−1差值是2,我们想办法将其缩小成1i+1和i-1差值是2,我们想办法将其缩小成1i+1和i−1差值是2,我们想办法将其缩小成1
3.设g[i]=f[i]−f[i−1],那么上面得式子可以化简为g[i]=(g[i+1]−g[i])∗p[i]3.设g[i]=f[i]-f[i-1],那么上面得式子可以化简为g[i]=(g[i+1]-g[i])*p[i]3.设g[i]=f[i]−f[i−1],那么上面得式子可以化简为g[i]=(g[i+1]−g[i])∗p[i]
4.我们分离变量g[i+1]=1−p[i]p[i]∗g[i]4.我们分离变量g[i+1]={1-p[i]\over p[i]}*g[i]4.我们分离变量g[i+1]=p[i]1−p[i]∗g[i]
5.根据定义f[r+1]=1,f[l−1]=0;并且g[i]=f[i]−f[i−1],那么∑i=lr+1g[i]=f[r+1]−f[l−1]=15.根据定义f[r+1]=1,f[l-1]=0;并且g[i]=f[i]-f[i-1],那么\sum_{i=l}^{r+1}g[i]=f[r+1]-f[l-1]=15.根据定义f[r+1]=1,f[l−1]=0;并且g[i]=f[i]−f[i−1],那么∑i=lr+1g[i]=f[r+1]−f[l−1]=1
6.g[l]+g[l+1]....+g[r+1]=g[l]+g[l]∗1−p[l]p[l]+....,我们设u[i]=1−p[i]p[i]那么后面g[l]+g[l]∗u[l]+g[l]∗u[l]∗u[l+1]...+g[l]∗u[l]∗...∗u[r]全部变成g[l]6.g[l]+g[l+1]....+g[r+1]=g[l]+g[l]*{1-p[l]\over p[l]}+....,我们设u[i]={1-p[i]\over p[i]}那么后面g[l]+g[l]*u[l]+g[l]*u[l]*u[l+1]...+g[l]*u[l]*...*u[r]全部变成g[l]6.g[l]+g[l+1]....+g[r+1]=g[l]+g[l]∗p[l]1−p[l]+....,我们设u[i]=p[i]1−p[i]那么后面g[l]+g[l]∗u[l]+g[l]∗u[l]∗u[l+1]...+g[l]∗u[l]∗...∗u[r]全部变成g[l]
7.现在我们相求f[l]从上面可知f[l]−f[l−1]=g[l],f[l−1]=0,那么f[l]=g[l]所以问题就变成了求g[l]7.现在我们相求f[l]从上面可知f[l]-f[l-1]=g[l],f[l-1]=0,那么f[l]=g[l]所以问题就变成了求g[l]7.现在我们相求f[l]从上面可知f[l]−f[l−1]=g[l],f[l−1]=0,那么f[l]=g[l]所以问题就变成了求g[l]
8.那么我们把6式子中得g[l]提出来g[l]∗(1+u[l]+u[l]∗u[l+1]+u[l]∗u[l+1]∗u[l+2]+.....u[l]∗u[l+1]∗....∗u[r])=18.那么我们把6式子中得g[l]提出来g[l]*(1+u[l]+u[l]*u[l+1]+u[l]*u[l+1]*u[l+2]+.....u[l]*u[l+1]*....*u[r])=18.那么我们把6式子中得g[l]提出来g[l]∗(1+u[l]+u[l]∗u[l+1]+u[l]∗u[l+1]∗u[l+2]+.....u[l]∗u[l+1]∗....∗u[r])=1
很明显我们可以用线段树维护区间乘法,如过我们直接维护u[1,r]的乘积然后再除以u[1,l−1]的值,很不幸这道题卡精度不能这样子求很明显我们可以用线段树维护区间乘法,如过我们直接维护u[1,r]的乘积然后再除以u[1,l-1]的值,很不幸这道题卡精度不能这样子求很明显我们可以用线段树维护区间乘法,如过我们直接维护u[1,r]的乘积然后再除以u[1,l−1]的值,很不幸这道题卡精度不能这样子求
我们应该考虑如何合并区间信息:对于每个线段树的节点它维护了一个区间[l,r][l,r][l,r],我们只看1个点的情况val1=u[l],两个点就是val2=u[l]+u[l]∗u[l+1],三个点就是val3=u[l]+u[l]∗u[l+1]+u[l]∗u[l+1]∗u[l+2],假设线段树左儿子是[l,l+1],右儿子是[l+2],那么合并就是val2+u[l]∗u[l+1]∗u[l+2]=val3val1=u[l],两个点就是val2=u[l]+u[l]*u[l+1],三个点就是val3=u[l]+u[l]*u[l+1]+u[l]*u[l+1]*u[l+2],假设线段树左儿子是[l,l+1],右儿子是[l+2],那么合并就是val2+u[l]*u[l+1]*u[l+2]=val3val1=u[l],两个点就是val2=u[l]+u[l]∗u[l+1],三个点就是val3=u[l]+u[l]∗u[l+1]+u[l]∗u[l+1]∗u[l+2],假设线段树左儿子是[l,l+1],右儿子是[l+2],那么合并就是val2+u[l]∗u[l+1]∗u[l+2]=val3
那么我们线段树要维护两个值:val=u[l]+u[l]∗u[l+1].....,sum=u[l]∗u[l+1]....;合并就是valleftson+sumleftson∗valrightson=valfather,sumleftson∗sumrightson=sumfatherval=u[l]+u[l]*u[l+1].....,sum=u[l]*u[l+1]....;合并就是val_{leftson}+sum_{leftson}*val_{rightson}=val_{father},sum_{leftson}*sum_{rightson}=sum_{father}val=u[l]+u[l]∗u[l+1].....,sum=u[l]∗u[l+1]....;合并就是valleftson+sumleftson∗valrightson=valfather,sumleftson∗sumrightson=sumfather
下面看代码:
#include <iostream>
#include <cstdio>
#include <stack>
#include <sstream>
#include <vector>
#include <map>
#include <cstring>
#include <deque>
#include <cmath>
#include <iomanip>
#include <queue>
#include <algorithm>
#include <set>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define Setw(a) fixed<<setprecision(a)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define hash Hash
#define next Next
#define count Count
#define pb push_back
#define f first
#define s second
using namespace std;
const int N = 1e5+10, mod = 1e9 + 7;
const double eps = 1e-10;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> PII;
template<typename T> void read(T &x)
{x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)
{read(first);read(args...);
}
struct node
{double x, w;
}tr[N<<2];
int n, q;
double a[N];
inline void pushup(int rt)
{tr[rt].w = tr[rt << 1].w * tr[rt << 1|1].w;tr[rt].x = tr[rt << 1].x + tr[rt << 1].w * tr[rt << 1|1].x;return;
}inline void build(int rt, int l, int r)
{if(l == r){tr[rt].x = a[l];tr[rt].w = a[l];return;}build(Lson);build(Rson);pushup(rt);
}inline void update(int rt, int l, int r ,int pos, double val)
{if(l == r){tr[rt].w = val;tr[rt].x = val;return;}if(pos <= mid) update(Lson,pos,val);else update(Rson,pos,val);pushup(rt);
}inline node query(int rt, int l, int r, int posl, int posr)
{if(posl <= l && posr >= r) return tr[rt];else {node left = (node){-INF,-INF};node right = (node){-INF,-INF};if(posl <= mid) left = query(Lson,posl,posr);if(posr > mid) right = query(Rson,posl,posr);if(left.w == -INF) return right;else if(right.w == -INF) return left;else {node res;res.w = left.w * right.w;res.x = left.x + left.w * right.x;return res;}}
}int main()
{read(n,q);_rep(i,1,n) {double l, r;cin >> l >> r;a[i] = 1.0 * l / r;a[i] = (1.0 - a[i]) / a[i];}build(1,1,n);while(q--){int op, pos;double l, r;read(op);if(op == 1){cin >> pos >> l >> r;double ans = (1.0 - l/r) / (l/r);update(1,1,n,pos,ans);}else {cin >> l >> r;double ans = query(1,1,n,l,r).x;cout << Setw(10) << 1.0 / (ans + 1.0) << endl;}}return 0;
}
Codeforces Round #370 (Div. 2)E. Memory and Casinos[期望概率+线段树区间合并]详细推导相关推荐
- Codeforces Round #538 (Div. 2) F. Please, another Queries on Array? 线段树 + 欧拉函数
传送门 文章目录 题意: 思路: 题意: 给你一个序列aaa,你需要实现两种操作: (1)(1)(1) 将[l,r][l,r][l,r]的aia_iai都乘rrr. (2)(2)(2) 求ϕ(∏i= ...
- Codeforces Round #620 (Div. 2) F2. Animal Observation (hard version) dp + 线段树
传送门 文章目录 题意: 思路: 题意: 比如下面这个图: 思路: 对于这个题,比较容易就能考虑到dpdpdp,设f[i][j]f[i][j]f[i][j]为到了第iii行,覆盖了[j,j+k−1][ ...
- Codeforces Round #345 (Div. 1) D. Zip-line 上升子序列 离线 离散化 线段树
D. Zip-line 题目连接: http://www.codeforces.com/contest/650/problem/D Description Vasya has decided to b ...
- Codeforces Round #439 (Div. 2) E. The Untended Antiquity 二维线段树||二维树状数组
http://codeforces.com/contest/869/problem/E 题意:n*m的矩阵,q次操作,三种类型 类型1:给指定矩阵加上围栏 类型2:给指定矩阵去掉围栏 类型3:查询两点 ...
- Codeforces Round #370 (Div. 2) A. Memory and Crow 水题
A. Memory and Crow 题目连接: http://codeforces.com/contest/712/problem/A Description There are n integer ...
- 组合计数 ---- Codeforces Round #370 (Div. 2)D. Memory and Scores[dp]
题目大意:Memory 和 Lexa分别取数,取ttt轮,每一轮取的数字的范围为[−k,k][−k,k][−k,k],并且将取的数字加他们的得分,问有多少种方案Memory的得分严格大于Lexa.Me ...
- Codeforces Round #699 (Div. 2) E.Sorting Books(贪心+DP / 线段树)超高质量题解,看不懂来打我 ~
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 E - Sorting Books 一排书架上有 nnn 本书排成一排,每本书上有一个颜色 aia_i ...
- Codeforces Round #197 (Div. 2): D. Xenia and Bit Operations(线段树)
题意:定义一个长度2^n的序列{a1, a2-an},序列相邻两个元素或运算之后再进行异或运算再进行或运算(两种运算交替进行)直到只剩下一个数字,这个数字即为序列的值,输入第一行两个数n,m表示序列的 ...
- Codeforces Round #807 (Div. 2) E. Mark and Professor Koro 二进制/线段树
题目分析 模拟题目不难发现,实际上擦除操作就是在模拟二进制加法进位.那么可以得到原题意的转述: 将每个 a [ i ] a[i] a[i]看作 2 a [ i ] 2^{a[i]} 2a[i],维护整 ...
最新文章
- php array_multisort对数据库结果多个字段进行排序
- html5 canvas绘制圆形进度实例
- hdu 5023 poj 2777(线段染色)2014 ACM/ICPC Asia Regional 广州 Online
- 计蒜客 A2232.程序设计:蒜厂年会-单调队列(双端队列(STL deque)实现)滑窗维护最小前缀和...
- 读取数据库名及表与表中的字段
- iphone怎么检测屏幕是否被点亮 (用UIApplication的Delegate)
- 辞职前一定要三思的八个问题
- python连接mysql的操作
- 生成静态libevent
- 再也不用装双系统和虚拟机了!——吐血推荐令Windows与Liunx合二为一的WSL2
- 数据结构与算法之队列
- 拓端tecdat|加速R语言代码的策略
- LaTeX伪代码写法总结
- 21天通关python 磁力_Python 实现 BT 种子转化为磁力链接 [实战]
- 华中师范大学计算机考研论坛,2020年华中师范大学计算机考研经验分享
- python停止程序_如何停止python程序
- NPIO 简单读写 EXCEL 小李子
- 微信公众号JSAPI支付对接
- GEEM2引擎微端架设基本教程
- App Extension