「算法笔记」期望 DP 入门
一、数学期望
1. 由来
在 \(17\) 世纪,有一个赌徒向法国著名数学家帕斯卡挑战,给他出了一道题目:甲乙两个人赌博,他们两人获胜的机率相等,比赛规则是先胜三局者为赢家,一共进行五局,赢家可以获得 \(100\) 法郎的奖励。当比赛进行到第四局的时候,甲胜了两局,乙胜了一局,这时由于某些原因中止了比赛,那么如何分配这 \(100\) 法郎才比较公平?
甲输掉后两局的可能性只有 \(\frac{1}{2} \times \frac{1}{2}=\frac{1}{4}\),也就是说甲赢得后两局或后两局中任意赢一局的概率为 \(1-\frac{1}{4}=\frac{3}{4}\),甲有 \(75\%\) 的期望获得 \(100\) 法郎;而乙期望赢得 \(100\) 法郎就得在后两局均击败甲,乙连续赢得后两局的概率为 \(\frac{1}{2}\times \frac{1}{2}=\frac{1}{4}\),即乙有 \(25\%\) 的期望获得 \(100\) 法郎奖金。
可见,虽然不能再进行比赛,但依据上述可能性推断,甲乙双方最终胜利的客观期望分别为 \(75\%\) 和 \(25\%\),因此甲应分得奖金的 \(100\times 75\%=75\) (法郎),乙应分得奖金的的 \(100×25\%=25\) (法郎)。这个故事里出现了“期望”这个词,数学期望由此而来。(¿)
(摘自百度百科)
2. 定义
数学期望是实验中每次可能结果的概率乘以其结果的总和,它的定义式为:
其中 \(i\) 是所有可能发生的事件,\(x_i\) 为事件的权值,\(p_i\) 为事件发生的概率。
3. 性质
设 \(C\) 为一个常数, \(X\) 和 \(Y\) 是两个随机变量。以下是数学期望的重要性质:
- 1. \(E(C)=C\)
- 2. \(E(CX)=CE(X)\)
- 3. 期望的 线性性:\(E(X+Y)=E(X)+E(Y)\)
- 4. 当 \(X\) 和 \(Y\) 相互独立时,\(E(XY)=E(X)E(Y)\)
二、例题
1. SP1026 FAVDICE - Favorite Dice
题目大意:一个 \(n\) 面的骰子,求期望掷几次能使得每一面都被掷到。\(n\leq 6000\)。
Solution:
结论:\(1+\frac{n}{n-1}+\frac{n}{n-2}+...+n=\sum_{i=1}^n \frac{n}{i}\)
令 \(f_i\) 表示已经掷出 \(i\) 个不同的面,还期望掷多少次能使得每一面都被掷到。
显然 \(f_n=0\)。
对于所有 \(f_i\ (i\neq n)\),有两种情况:
- 有 \(\frac{i}{n}\) 的概率掷到重复的面,则还需掷 \(f_i\) 次。
- 有 \(\frac{n-i}{n}\) 的概率掷到新的面,则还需掷 \(f_{i+1}\) 次。
\(f_i=(\frac{i}{n} f_i+\frac{n-i}{n} f_{i+1})+1\)
整理得,\(f_i=f_{i+1}+\frac{n}{n-i}\)
因此 \(Ans=f_0=\sum\limits_{i=n-1}^{0} \frac{n}{n-i}=\sum_{i=1}^n \frac{n}{i}\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n;
double ans;
signed main(){
scanf("%lld",&t);
while(t--){
scanf("%lld",&n),ans=0;
for(int i=1;i<=n;i++)
ans+=1.0*n/i;
printf("%.2lf\n",ans);
}
return 0;
}
2. BZOJ 1419 Red is good
题目大意:桌面上有 \(R\) 张红牌和 \(B\) 张黑牌,随机打乱顺序后放在桌面上,开始一张一张地翻牌,翻到红牌得到 \(1\) 美元,黑牌则付出 \(1\) 美元。可以随时停止翻牌,在最优策略下平均能得到多少钱。\(0\leq R,B \leq 5000\)。
Solution:
令 \(f_{r,b}\) 表示剩下 \(r\) 张红牌、\(b\) 张黑牌的期望收益。
首先考虑边界情况。
当 \(r=0\),即目前已经没有红牌时,停止翻牌,则 \(f_{r,b}=0\)。当 \(b=0\),即剩下的牌没有黑牌时,肯定会把剩下的红牌全部翻掉,则 \(f_{r,b}=r\)。
讨论其他情况。
有 \(\frac{r}{r+b}\) 的概率翻到一张红牌,并带来 \(1\) 的收益;有 \(\frac{b}{r+b}\) 的概率翻到一张黑牌,并带来 \(1\) 的损失。
那么显然 \(f_{r,b}=\max(0,\frac{r}{r+b}(1+f_{r-1,b})+\frac{b}{r+b}(-1+f_{r,b-1})\)。因为我们采用的是最优策略,所以当此时的局面已经不足以带来大于 \(0\) 的期望收益时,应该停止翻牌,所以最后还要和 \(0\) 取 \(max\)。
由于卡空间,需要使用滚动数组。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5010;
int n,m;
double f[2][N],ans;
signed main(){
scanf("%lld%lld",&n,&m);
for(int r=1;r<=n;r++){
f[r%2][0]=1.0*r;
for(int b=1;b<=m;b++)
f[r%2][b]=max(0.0,1.0*r/(r+b)*(1+f[(r-1)%2][b])+1.0*b/(r+b)*(-1+f[r%2][b-1]));
}
printf("%.6lf\n",1.0*floor(f[n%2][m]*1e6)/1e6);
return 0;
}
3. BZOJ 4318 OSU!
题目大意:给出一串数,每个数字有 \(a_i\) 的概率是 \(\text{O}\),这串数字的分数定义为每一段极长连续的 \(\text{O}\) 的长度的立方和,\(\text{OXXOO}\) 的分数就是 \(1^3+2^3=9\),求期望分数。\(N\leq 10^5\)。
Solution:
令 \(y_i\) 表示到 \(i\) 为止连续打出多少个 \(\text{O}\)。
有 \(p=a_i\) 的概率打出 \(\text{O}\),则有 \(p\) 的概率 \(y_i=y_{i-1}+1\);有 \(1-p\) 的概率打出的不是 \(\text{O}\),则有 \(1-p\) 的概率 \(y_i=0\)。
\(E(y_i)=E(p\times (y_{i-1}+1))=p\times (E(y_{i-1})+1)\)
因为 \((x+1)^3=x^3+3x^2+3x+1\),所以还需要维护平方和。每打出 \(1\) 个 \(\text{O}\),答案 \((x+1)^3\) 比原答案 \(x^3\) 相比多了 \(3x^2+3x+1\)。
\(E({y_i}^2)=E(p\times (y_{i-1}+1)^2)=p\times (E({y_{i-1}}^2)+2\times E(y_{i-1})+1)\)
可以分别用 \({f_1}_i,{f_2}_i\) 维护 \(E(y_i),E({y_i}^2)\)。
\({f_1}_{i}=p\times ({f_1}_{i-1}+1)\)
\({f_2}_{i}=p\times({f_2}_{i-1}+2\times {f_1}_{i-1}+1)\)
那么 \({ans}_i={ans}_{i-1}+p\times (3\times {f_2}_{i-1}+3\times {f_1}_{i-1}+1)\),最终的答案为 \({ans}_{n}\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int n;
double a[N],f1[N],f2[N],ans[N];
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lf",&a[i]);
for(int i=1;i<=n;i++){
f1[i]=a[i]*(f1[i-1]+1);
f2[i]=a[i]*(f2[i-1]+2*f1[i-1]+1);
ans[i]=ans[i-1]+a[i]*(3*f2[i-1]+3*f1[i-1]+1);
}
printf("%.1lf\n",ans[n]);
return 0;
}
4. HDU 4035 Maze
题目大意:有一个树形的迷宫,有 \(N\) 个房间以及 \(N-1\) 条通道将它们连通,一开始在 \(1\) 号房间,每进入一个房间 \(i\),有 \({kill}_i\) 的概率被陷阱杀死回到房间 \(1\),有 \(s_i\) 的概率找到出口逃离迷宫,如果没有找到出口也没有被杀,那么就在与该房间相连的通道中等概率随机选一条走,求逃离迷宫所需要走的通道数的期望值。(如果不能逃离输出impossible
)。\(T\leq 30,N\leq 10^4\)。
Solution:
令 \(f_i\) 表示目前在节点 \(i\) 上的期望步数。
对于任意一个节点 \(u\),\(f_u={kill}_u f_1+s_u\times 0+\frac{1-{kill}_u-s_u}{{deg}_u}\sum\limits_{v} (f_v+1)\)(节点 \(v\) 与节点 \(u\) 相连)。
把 \(s_u\times 0\) 这一项省去,再把最后一项拆出来,则 \(f_u={kill}_u f_1+\frac{1-{kill}_u-s_u}{{deg}_u}\sum\limits_{v} f_v+\frac{1-{kill}_u-s_u}{{deg}_u}\sum\limits_{v} 1)\),也就是 \(f_u={kill}_u f_1+\frac{1-{kill}_u-s_u}{{deg}_u}\sum\limits_{v\in {fa_u}} f_{v}+\frac{1-{kill}_u-s_u}{{deg}_u}\sum\limits_{v\in {son_u}} f_v+(1-{kill}_u-s_u)\)。
注意到:1. 对于任意一个节点 \(u\),式子中都有 \(f_1\)。 2. 如果 \(u\) 为叶子节点,那么 \(v\) 只有 \(u\) 的父亲(叶子节点没有儿子)。
可以发现,叶子节点的式子可以表示成:\(f_u=a_u\times f_1+b_u\times f_{{fa}_{u}}+c_u\),其中 \(a_u\)、\(b_u\) 以及 \(c_u\) 都是常数。
设 \(u\) 是 \(i\) 的父亲,将 \(f_i=a_i\times f_1+b_i\times f_u+c_i\) 代入最开始的那个式子得:
\(f_u={kill}_u f_1+\frac{1-{kill}_u-s_u}{{deg}_u}\sum\limits_{v\in {fa_u}} f_{v}+\frac{1-{kill}_u-s_u}{{deg}_u}\sum(a_i\times f_1+b_i\times f_u+c_i)+(1-{kill}_u-s_u)\)
那么:
\((1-\frac{1-{kill}_u-s_u}{{deg}_u}\times \sum b_i)\times f_u=({kill}_u+\frac{1-{kill}_u-s_u}{{deg}_u}\times \sum a_i)\times f_1\)
\(+\frac{1-{kill}_u-s_u}{{deg}_u}\sum\limits_{v\in{fa_u}} f_v+(1-{kill}_u-s_u+\frac{1-{kill}_u-s_u}{{deg}_u}\times \sum c_i)\)。
整理一下式子,可以得到:
\(\displaystyle f_u=\frac{({kill}_u+\frac{1-{kill}_u-s_u}{{deg}_u}\times \sum a_i)}{1-\frac{1-{kill}_u-s_u}{{deg}_u}\times \sum b_i}\times f_1\)
\(\displaystyle+\frac{\frac{1-{kill}_u-s_u}{{deg}_u}}{1-\frac{1-{kill}_u-s_u}{{deg}_u}\times \sum b_i}f_{{fa}_u}+\frac{(1-{kill}_u-s_u+\frac{1-{kill}_u-s_u}{{deg}_u}\times \sum c_i)}{1-\frac{1-{kill}_u-s_u}{{deg}_u}\times \sum b_i}\)
把这个式子和 \(f_u=a_u\times f_1+b_u\times f_{{fa}_{u}}+c_u\) 对比,可以发现,所有的式子都能和叶子节点的式子一样被表示成 \(f_u=a_u\times f_1+b_u\times f_{{fa}_{u}}+c_u\) 的形式。
这意味着我们能从叶子节点一直往上推,到根节点的时候就能得到答案。
\(f_1=a_1\times f_1+b_1\times 0+c_1\),所以 \(f_1=\frac{c_1}{1-a_1}\)。\(a_1=1\) 时无解。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e4+5;
int t,n,m,x,y,tot,cnt,hd[N],to[N<<1],nxt[N<<1];
double k[N],s[N],a[N],b[N],c[N];
void add(int x,int y){
to[++cnt]=y,nxt[cnt]=hd[x],hd[x]=cnt;
}
void dfs(int x,int fa){
double num=0,ka=0,kb=0,kc=0,p=1.0-k[x]-s[x];
a[x]=b[x]=c[x]=0;
for(int i=hd[x];i;i=nxt[i]){
int y=to[i];
if(y!=fa) ++num,dfs(y,x),ka+=a[y],kb+=b[y],kc+=c[y];
}
if(x!=1) ++num;
if(num==1&&x!=1) a[x]=k[x],b[x]=1.0-k[x]-s[x],c[x]=b[x]; //叶子节点
else a[x]=(k[x]+p/num*ka)/(1-p/num*kb),b[x]=(p/num)/(1-p/num*kb),c[x]=(p+p/num*kc)/(1-p/num*kb); //非叶子节点
}
signed main(){
scanf("%lld",&t);
while(t--){
cnt=0,memset(hd,0,sizeof(hd));
scanf("%lld",&n);
for(int i=1;i<n;i++){
scanf("%lld%lld",&x,&y);
add(x,y),add(y,x);
}
for(int i=1;i<=n;i++){
scanf("%lf%lf",&k[i],&s[i]);
k[i]/=100,s[i]/=100;
}
dfs(1,0);
if(fabs(1-a[1])<1e-9) printf("Case %lld: impossible\n",++tot); //卡精度
else printf("Case %lld: %.6lf\n",++tot,c[1]/(1-a[1]));
}
return 0;
}
「算法笔记」期望 DP 入门的更多相关文章
- 「算法笔记」树形 DP
一.树形 DP 基础 又是一篇鸽了好久的文章--以下面这道题为例,介绍一下树形 DP 的一般过程. POJ 2342 Anniversary party 题目大意:有一家公司要举行一个聚会,一共有 \ ...
- 「算法笔记」数位 DP
一.关于数位 dp 有时候我们会遇到某类问题,它所统计的对象具有某些性质,答案在限制/贡献上与统计对象的数位之间有着密切的关系,有可能是数位之间联系的形式,也有可能是数位之间相互独立的形式.(如求满足 ...
- 「算法笔记」快速数论变换(NTT)
一.简介 前置知识:多项式乘法与 FFT. FFT 涉及大量 double 类型数据操作和 \(\sin,\cos\) 运算,会产生误差.快速数论变换(Number Theoretic Transfo ...
- 「算法笔记」状压 DP
一.关于状压 dp 为了规避不确定性,我们将需要枚举的东西放入状态.当不确定性太多的时候,我们就需要将它们压进较少的维数内. 常见的状态: 天生二进制(开关.选与不选.是否出现--) 爆搜出状态,给它 ...
- 「算法笔记」2-SAT 问题
一.定义 k-SAT(Satisfiability)问题的形式如下: 有 \(n\) 个 01 变量 \(x_1,x_2,\cdots,x_n\),另有 \(m\) 个变量取值需要满足的限制. 每个限 ...
- 「算法笔记」Polya 定理
一.前置概念 接下来的这些定义摘自 置换群 - OI Wiki. 1. 群 若集合 \(s\neq \varnothing\) 和 \(S\) 上的运算 \(\cdot\) 构成的代数结构 \((S, ...
- 「算法笔记」旋转 Treap
一.引入 随机数据中,BST 一次操作的期望复杂度为 \(\mathcal{O}(\log n)\). 然而,BST 很容易退化,例如在 BST 中一次插入一个有序序列,将会得到一条链,平均每次操作的 ...
- 「算法笔记」FHQ-Treap
右转→https://www.cnblogs.com/mytqwqq/p/15057231.html 下面放个板子 (禁止莱莱白嫖板子) P3369 [模板]普通平衡树 #include<bit ...
- 「算法笔记」Min_25 筛
戳 这里(加了密码).虽然写的可能还算清楚,但还是不公开了吧 QwQ. 真的想看的 私信可能会考虑给密码 qwq.就放个板子: //LOJ 6053 简单的函数 f(p^c)=p xor c #inc ...
随机推荐
- hive向mysql导入数据sqoop命令出错
报错信息: java.lang.Exception: java.io.IOException: java.lang.ClassNotFoundException: info at org.apache ...
- Swift-技巧(十一)重写运算符
摘要 基础数据的运算可以直接使用四则运算符.在 Swift 中也可以通过重写四则运算符的方式,让 struct 或者 class 创建的结构体或者对象也能像基础数据那样直接使用四则运算符. Swift ...
- day04 orm操作
day04 orm操作 昨日内容回顾 小白必会三板斧 request对象方法 静态文件 请求方式 python链接数据库 django链接数据库 小白必会三板斧 HttpResponse :返回前端浏 ...
- 【leetcode】208. Implement Trie (Prefix Tree 字典树)
A trie (pronounced as "try") or prefix tree is a tree data structure used to efficiently s ...
- Siebel调用WebService
Siebel可以调用外部系统的接口,通过WebService的接入方式实现,所在的项目都是通过ESB,其他系统的接口都要经过ESB,由ESB提供WSDL文档,通过Siebel调用. 一.修改Tools ...
- 【AWS】【TroubleShooting】EC2实例无法使用SSH远程登陆(EC2 failure for SSH connection)
1. Login AWS web console and check the EC2 instance.
- OpenStack之二: 安装OpenStack的yum源及相关组件
#: 在所有节点执行 [root@localhost ~]# yum install centos-release-openstack-stein -y #: 安装相关组件(只在管理端和计算几点安装) ...
- OpenStack之一:初始化环境
初始化环境必须在左右节点执行 #:注意node节点要使用7.2 #: 关闭NetworkManager [root@localhost ~]# systemctl stop NetworkManage ...
- Non-terminating decimal expansion; no exact representable decimal result.
Non-terminating decimal expansion; no exact representable decimal result. 翻译为:非终止十进制扩展; 没有确切的可表示的小数 ...
- 【Matlab】imagesc的使用
imagesc(A) 将矩阵A中的元素数值按大小转化为不同颜色,并在坐标轴对应位置处以这种颜色染色 imagesc(x,y,A) x,y决定坐标范围 x,y应是两个二维向量,即x=[x1 x2],y= ...