CTSC 2017 游戏[概率dp 线段树]
小 R 和室友小 B 在寝室里玩游戏。他们一共玩了 $n$ 局游戏,每局游戏的结果要么是小 R 获胜,要么是小 B 获胜。
第 $1$ 局游戏小 R 获胜的概率是 $p_1$,小 B 获胜的概率是 $1-p_1$。除了第一局游戏之外,每一局游戏小 R 获胜的概率与上一局游戏小 R 是否获胜有关。
具体来说:
- 如果第 $i-1\ (1< i\le n)$ 局游戏小 R 获胜,那么第 $i$ 局游戏小 R 获胜的概率为 $p_i$,小 B 获胜的概率为 $1-p_i$。
- 如果第 $i-1\ (1< i\le n)$ 局游戏小 B 获胜,那么第 $i$ 局游戏小 R 获胜的概率为 $q_i$,小 B 获胜的概率为 $1-q_i$。
小 D 时常过来看小 R 和小 B 玩游戏,因此他知道某几局游戏的结果。他想知道在他已知信息的条件下,小 R 在 $n$ 局游戏中获胜总局数的期望是多少。
小 D 记性不太好,有时他会回忆起某局游戏的结果,并把它加入到已知信息中;有时他会忘记之前某局游戏结果,并把它从已知信息中删除。你的任务是:每当小 D 在已知信息中增加或删除一条信息时,根据小 D 记得的已知信息,帮助小 D 计算小 R 在 $n$ 局游戏中获胜总局数的期望是多少。
需要注意的是:如果小 D 忘了一局游戏的结果,之后又重新记起,两次记忆中的游戏结果不一定是相同的。你不需要关心小 D 的记忆是否与实际情况相符,你只需要根据他的记忆计算相应的答案。
输入格式
第一行两个正整数 $n,m$ 和一个字符串 $type$。表示小 R 和小 B 一共玩了 $n$ 局游戏,小 D 一共进行了 $m$ 次修改已知信息的操作,该数据的类型为 $type$。$type$ 字符串是为了能让大家更方便地获得部分分,你可能不需要用到这个输入,其具体含义见限制与约定。
接下来 $n$ 行,第 $1$ 行包含一个实数 $p_1$,表示第一局比赛小R获胜的概率是 $p_1$。第 $i\ (1< i \le n)$ 行包含两个实数 $p_i,q_i$。表示在第 $i-1$ 局游戏小 R 获胜的情况下,第 $i$ 局游戏小 R 获胜的概率是 $p_i$;$q_i$ 表示在第 $i-1$ 局游戏小 B 获胜的情况下,第 $i$ 局游戏小 R 获胜的概率是 $q_i$。
接下来 $m$ 行,每行描述一个小 D 已知信息的变化,操作分为两类。
add i c表示小 D 回忆起了第 $i$ 局比赛的结果,并把它加入到已知信息中。若 $c=0$ 表示第 $i$ 局比赛小 B 获胜,若 $c=1$ 表示第 $i$ 局比赛小 R 获胜。数据保证 $i,c$ 均为整数且 $1\le i \le n,0\le c \le 1$,如果这个操作不是第一个操作,保证在上一个操作结束后的已知信息中没有第 $i$ 局比赛的结果。del i表示小 D 忘记了第 $i$ 局比赛的结果,并把它从已知信息中删除。数据保证 $i$ 是整数且 $1\le i \le n$,保证在上一个操作结束后的已知信息中有第 $i$ 局比赛的结果。
输出格式
对于每个操作,输出一行实数,表示操作结束后,在当前已知信息的条件下,小R在 $n$ 局游戏中总共获胜的局数的期望是多少。
样例一
input
3 3 A
0.3
0.5 0.2
0.9 0.8
add 1 1
add 3 0
del 1
output
2.350000
1.333333
0.432749
explanation
运用贝叶斯公式
第一问
$$p(x_2=1|x_1=1)=0.5,p(x_3=1|x_1=1)=0.5*0.9+0.5*0.8=0.85,E(x_1+x_2+x_3|x_1=1)=0.5+0.85+1=2.35$$
第二问
$$p(x_2=1|x_1=1,x_3=0)=\frac{p(x_3=0|x_1=1,x_2=1)p(x_2=1|x_3=0)}{p(x_3=0|x_1=1)} \approx 0.333,E(x_1+x_2+x_3|x_1=1,x_3=0) \approx 1.333$$
第三问
$$p(x_2=1|x_3=0)=\frac{p(x_3=0|x_2=1)p(x_2=1)}{p(x_3=0)}$$
其中
$$p(x_3=0|x_2=1)=0.1,p(x_2=1)=0.3*0.5+0.7*0.2=0.29,p(x_3=0)=0.29*0.1+0.71*0.2=0.171$$
所以
$$p(x_2=1|x_3=0)=0.1*0.29/0.171 \approx 0.16959$$
$$p(x_1=1|x_3=0)=\frac{p(x_3=0|x_1=1)p(x_1=1)}{p(x_3=0)}$$
其中
$$p(x_3=0|x_1=1)=0.5*0.1+0.5*0.2=0.15,p(x_1=1)=0.3,p(x_3=0)=0.171$$
所以
$$p(x_1=1|x_3=0)=0.15*0.3/0.171 \approx 0.26316$$
$$E(x_1+x_2+x_3|x_3=0) \approx 0.43275$$
样例二
见样例数据下载。
样例三
见样例数据下载。
评分标准
如果你的答案与正确答案的绝对误差在 $10^{-4}$ 以内,则被判定为正确。
如果你的所有答案均为正确,则得满分,否则得 0 分。
请注意输出格式:每行输出一个答案,答案只能为一个实数。每行的长度不得超过 50。错误输出格式会被判定为 0 分。
限制与约定
对于100%的数据,$1\le n\le 200000, 1\le m \le 200000,0 < p_i,q_i < 1$。
对于100%的数据,输入保留最多四位小数。
本题共有20个数据点,每个数据点5分,每个测试点的具体约定如下表:
| 测试点 | $n$ | $m$ | 数据类型 |
|---|---|---|---|
| 1-2 | $\le 10$ | $\le 20$ | A |
| 3-4 | $\le 100$ | $\le 100$ | B |
| 5-6 | $\le 1000$ | $\le 5000$ | A |
| 7-9 | $\le 2000$ | $\le 5000$ | B |
| 10-13 | $\le 10000$ | $\le 200000$ | B |
| 14-15 | $\le 200000$ | $\le 200000$ | C |
| 16-17 | D | ||
| 18-20 | A |
数据类型的含义:
A:无限制
B:$\forall i > 1,|p_i-q_i| > 0.999$
C:同一时刻,小 D 最多只有 1 条已知信息
D:同一时刻,小 D 最多只有 5 条已知信息
时间限制:$1\texttt{s}$
空间限制:$512\texttt{MB}$
小R教你学数学
你可能会用到以下公式
条件概率的计算方法
我们记 $p(A|B)$ 表示在已知事件 $B$ 发生时事件 $A$ 发生的概率,条件概率可以用以下公式计算:
$$p(A|B)=\frac{p(AB)}{p(B)}$$
其中$p(AB)$表示事件 $B$ 和事件 $A$ 同时发生的概率,$p(B)$ 表示事件 $B$ 发生的概率。
贝叶斯公式(Bayes)
由条件概率的计算方法,我们容易得到贝叶斯公式
$$p(A|B)=\frac{p(B|A)p(A)}{p(B)}$$
全概率公式
如果随机变量 $x$ 有 $k$ 个取值,分别为 $x_1,x_2,\ldots,x_k$ 那么
$$p(A)=\sum_{i=1}^k p(A|x=x_i)p(x=x_i)$$
温馨提示
在本题中,如果你希望获得全部的分数,你可能需要考虑由于浮点数运算引入的误差。只使用加法和乘法运算不会引入太大的误差,但请谨慎使用减法和除法。
- 两个大小相近的数相减可以引入非常大的相对误差。
- 如果一个矩阵的行列式值非常小,那么求解该矩阵的逆可以带来相当大的误差。
当然,如果你的算法在数学上是正确的,但没有考虑浮点数运算的误差问题,可能仍然可以获得一部分的分数。
下载
【题解】

贝叶斯证明;
\[
\begin{align}
&bayes公式:\\
P(A|B)P(B) &= P(A\ \cap B) \Leftrightarrow P(A|B) = \frac{P(B|A)P(A)}{P(B)} \\
&P(x_i=1|x_l=a,x_r=b)(1\lt i \le r)\\
&=\frac{P(x_i=1,x_l=a,x_r=b)}{P(x_l=a,x_r=b)}\\
&=\frac{P(x_i=1,x_l=a,x_r=b)}{P(x_l=a)P(x_r=b|x_l=a)}\\
&=\frac{P(x_i=1,x_r=b|x_l=a)}{P(x_r=b|x_l=a)}\\
\end{align}
\]
【代码】
#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#define fi first
using std::map;
const int N=2e5+;
int n,m;double ans,p[N],q[N];char opt[];
map<int,int>S;
map<int,int>::iterator it,nxt,pre;
struct Matrix{
double s[][];
Matrix(){memset(s,,sizeof s);}
Matrix operator +(const Matrix &a)const{
Matrix c;
for(int i=;i<;i++){
for(int j=;j<;j++){
c.s[i][j]=s[i][j]+a.s[i][j];
}
}
return c;
}
Matrix operator *(const Matrix &a)const{
Matrix c;
for(int i=;i<;i++){
for(int j=;j<;j++){
for(int k=;k<;k++){
c.s[i][j]+=s[i][k]*a.s[k][j];
}
}
}
return c;
}
};
struct data{Matrix mul,sum;}tr[N<<];
data operator +(const data &a,const data &b){
data c;
c.mul=a.mul*b.mul;
c.sum=a.mul*b.sum+a.sum*b.mul;
return c;
}
#define lch k<<1
#define rch k<<1|1
void build(int k,int l,int r){
if(l==r){
tr[k].mul.s[][]=-q[l];
tr[k].mul.s[][]=q[l];
tr[k].mul.s[][]=-p[l];
tr[k].mul.s[][]=p[l]; tr[k].sum.s[][]=q[l];
tr[k].sum.s[][]=p[l];
return ;
}
int mid=l+r>>;
build(lch,l,mid);
build(rch,mid+,r);
tr[k]=tr[lch]+tr[rch];
}
data query(int k,int l,int r,int x,int y){
if(l==x&&r==y) return tr[k];
int mid=l+r>>;
if(y<=mid) return query(lch,l,mid,x,y);
else if(x>mid) return query(rch,mid+,r,x,y);
else return query(lch,l,mid,x,mid)+query(rch,mid+,r,mid+,y);
}
double ask(int l,int r){
data tmp=query(,,n+,l+,r);
return tmp.sum.s[S[l]][S[r]]/tmp.mul.s[S[l]][S[r]];
}
int main(){
scanf("%d%d%*s%lf",&n,&m,&p[]);
for(int i=;i<=n;i++) scanf("%lf%lf",p+i,q+i);
p[]=q[]=;S[]=;S[n+]=;
build(,,n+);
ans=ask(,n+);
for(int i=m,x,y;i;i--){
scanf("%s%d",opt,&x);
if(opt[]=='a'){
scanf("%d",&y);S[x]=y;
it=S.lower_bound(x);
nxt=pre=it;pre--,nxt++;
ans+=ask(pre->fi,it->fi);
ans+=ask(it->fi,nxt->fi);
ans-=ask(pre->fi,nxt->fi);
}
else{
it=S.lower_bound(x);
nxt=pre=it;pre--,nxt++;
ans-=ask(pre->fi,it->fi);
ans-=ask(it->fi,nxt->fi);
ans+=ask(pre->fi,nxt->fi);
S.erase(it);
}
printf("%.10lf\n",ans);
}
return ;
}
CTSC 2017 游戏[概率dp 线段树]的更多相关文章
- [BZOJ5461][LOJ#2537[PKUWC2018]Minimax(概率DP+线段树合并)
还是没有弄清楚线段树合并的时间复杂度是怎么保证的,就当是$O(m\log n)$吧. 这题有一个显然的DP,dp[i][j]表示节点i的值为j的概率,转移时维护前缀后缀和,将4项加起来就好了. 这个感 ...
- LOJ2537. 「PKUWC2018」Minimax【概率DP+线段树合并】
LINK 思路 首先暴力\(n^2\)是很好想的,就是把当前节点概率按照权值大小做前缀和和后缀和然后对于每一个值直接在另一个子树里面算出贡献和就可以了,注意乘上选最大的概率是小于当前权值的部分,选最小 ...
- [tsA1490][2013中国国家集训队第二次作业]osu![概率dp+线段树+矩阵乘法]
这样的题解只能舔题解了,,,qaq 清橙资料里有.. #include <iostream> #include <cstdio> #include <cstdlib> ...
- ZOJ 3349 Special Subsequence 简单DP + 线段树
同 HDU 2836 只不过改成了求最长子串. DP+线段树单点修改+区间查最值. #include <cstdio> #include <cstring> #include ...
- hdu 3016 dp+线段树
Man Down Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...
- cf834D(dp+线段树区间最值,区间更新)
题目链接: http://codeforces.com/contest/834/problem/D 题意: 每个数字代表一种颜色, 一个区间的美丽度为其中颜色的种数, 给出一个有 n 个元素的数组, ...
- [JLOI2013]卡牌游戏 概率DP
[JLOI2013]卡牌游戏 概率DP 题面 \(dfs\)复杂度爆炸,考虑DP.发现决策时,我们只用关心当前玩家是从庄家数第几个玩家与当前抽到的牌是啥.于是设计状态\(f[i][j]\)表示有\(i ...
- Codeforces Round #620 F2. Animal Observation (hard version) (dp + 线段树)
Codeforces Round #620 F2. Animal Observation (hard version) (dp + 线段树) 题目链接 题意 给定一个nm的矩阵,每行取2k的矩阵,求总 ...
- 【BZOJ-2892&1171】强袭作战&大sz的游戏 权值线段树+单调队列+标记永久化+DP
2892: 强袭作战 Time Limit: 50 Sec Memory Limit: 512 MBSubmit: 45 Solved: 30[Submit][Status][Discuss] D ...
随机推荐
- ML学习笔记之TF-IDF原理及使用
0x00 什么是TF-IDF TF-IDF(Term Frequency-Inverse Document Frequency, 词频-逆文件频率). # 是一种用于资讯检索与资讯探勘的常用加权技术. ...
- HTML+CSS+JS综合练习(动态验证版)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 用友U9 UFSoft.UBF.Business.Session
Session的概念 在现在UBF中,Session的本意是work unit,即持久层的一个边界,非常轻,主要用作批量提交,并标识这次批量提交的边界,不涉及到事务等概念. 当前ISession可以通 ...
- python基础05day--函数
一 函数知识体系 什么是函数?为什么要用函数?函数的分类:内置函数与自定义函数如何自定义函数 语法 定义有参数函数,及有参函数的应用场景 定义无参数函数,及无参函数的应用场景 定义空函数,及空函数的应 ...
- Guava入门
其实我用guava差不多大半年时间了,发现guava真的特别好用,又会使代码变得很简洁,最近又系统的学习了一下,大致讲一下
- element-ui 上传图片或视频时,先回显在上传
<el-upload class="upload-demo" ref="vidos" :action="URL+'/api/post/file' ...
- 排序算法的c++实现——插入排序
插入排序的思想是:给定一个待排序的数组,我们从中选择第一个元素作为有序的基态(单个元素肯定是有序的), 然后从剩余的元素中选择一个插入到有序的基态中,使插入之后的序列也是有序状态,重复此过程,直到全部 ...
- 复盘一篇讲sklearn库的文章(下)
skleran-处理流程 获取数据 以用sklearn的内置数据集, 先导入datasets模块. 最经典的iris数据集作为例子. from sklearn import datasets iris ...
- URI与URL详解
URL 与 URI 很多人会混淆这两个名词. URL:(Uniform/Universal Resource Locator 的缩写,统一资源定位符). URI:(Uniform Resource I ...
- Vue之Action
(1)同步与异步 在 mutation 中混合异步调用会导致你的程序很难调试. 例如,当你调用了两个包含异步回调的 mutation 来改变状态,你怎么知道什么时候回调和哪个先回调呢? 这就是为什么我 ...