掷到 6、全程偶数的期望次数
题
一颗公平骰子反复掷,出现 6 就停。已知从头到尾掷出的每个点数都是偶数,求掷骰次数的条件期望。
一句话
答案是 \(3/2\),不是 3——"全程偶数"不是把骰子换成只有 \(\{2,4,6\}\) 的三面骰,而是只保留那些没来得及出奇数就碰到 6 的序列。越长的序列越可能混进奇数,被筛掉;留下来的都偏短。
关键技巧
把条件改写成停止规则。 定义新停时 \(M\) = 首次掷出 \(\{1, 3, 5, 6\}\) 中任一点的时刻。于是:
- 事件 \(A\)(全程偶数)\(\iff\) \(M\) 那一次掷出的是 6——在出现 6 之前没有奇数,等价于 \(\{1,3,5,6\}\) 里第一个出现的是 6。
- 在 \(A\) 上,\(N = M\)。
\(M\) 之前的每一掷都是 2 或 4,\(M\) 那一掷在 \(\{1,3,5,6\}\) 上均匀且与 \(M\) 独立——"掷了多少个 2/4 才停"不影响"停在哪个点"。所以
\[ E[N \mid A] = E[M \mid X_M = 6] = E[M] = \frac{1}{4/6} = \frac32 \]
顺带 \(P(A) = P(X_M = 6) = \frac14\)。
解
直接算也就两行。\(N = n\) 且全程偶数,意味着前 \(n-1\) 次是 2 或 4、第 \(n\) 次是 6:
\[ P(N = n,\ A) = \left(\tfrac13\right)^{n-1} \cdot \tfrac16, \qquad P(A) = \sum_{n\ge1} \left(\tfrac13\right)^{n-1} \tfrac16 = \tfrac14 \]
\[ P(N = n \mid A) = \tfrac23 \left(\tfrac13\right)^{n-1}, \qquad E[N \mid A] = \frac{1}{2/3} = \frac32 \]
条件分布是成功率 \(\frac23\) 的几何分布——正好就是"每掷一次有 \(\frac46\) 的机会停下"的 \(M\)。
延伸
- 错在哪:答 3 的人默认了"已知全偶 = 每一掷都从 \(\{2,4,6\}\) 均匀抽"。这把条件当成了对过程的改造,实际上条件是对样本路径的筛选。前者停止概率每步 \(\frac13\),后者每步 \(\frac23\)——奇数点并没有消失,它们以"让这条路径作废"的方式参与了停止。
- 一般化:掷到出现目标集 \(S\) 为止,已知全程避开禁区 \(B\)(\(S \cap B = \varnothing\)),则 \(N \mid A\) 服从几何分布,成功率 \(\frac{|S| + |B|}{6}\),期望 \(\frac{6}{|S|+|B|}\)。本题 \(|S| = 1\)、\(|B| = 3\),给 \(\frac64\)。
- 同一个坑的其他面孔:两个孩子问题 与 Monty Hall 都是"信息怎么来的"决定条件概率——条件不是凭空加在世界上的限制,而是一次观察。
- 检验直觉的办法:把条件化写成模拟里的
if ok:过滤,而不是改写掷骰函数——代码结构本身就会告诉你哪个模型是对的。
数值验证
几何级数精确解、错误模型、拒绝采样与等价停止规则两路蒙特卡洛:
from fractions import Fraction as F
import random
# 精确:P(N = n 且全程偶数) = (1/3)^(n-1) * (1/6),几何级数求和
r, c = F(1, 3), F(1, 6)
PA = c / (1 - r) # sum_n c r^(n-1)
EN = c / (1 - r) ** 2 / PA # sum_n n c r^(n-1) / P(A)
print(PA, EN) # 1/4 3/2
print([c * r ** (n - 1) / PA for n in (1, 2, 3)])
# [Fraction(2, 3), Fraction(2, 9), Fraction(2, 27)] -> 几何分布 p = 2/3
# 错误模型:只在 {2,4,6} 里掷直到 6
print(F(1) / F(1, 3)) # 3
# 等价停止规则:掷到 {1,3,5,6} 之一就停,停时恰为 6 才算数
random.seed(6)
T, kept, tot, tot_eq, cnt_eq = 10 ** 6, 0, 0, 0, 0
for _ in range(T):
n, ok = 0, True
while True:
x = random.randint(1, 6); n += 1
if x % 2: ok = False
if x == 6: break
if ok: kept += 1; tot += n
n = 0
while True:
x = random.randint(1, 6); n += 1
if x in (1, 3, 5, 6): break
tot_eq += n; cnt_eq += 1
print(kept / T, tot / kept, tot_eq / cnt_eq) # 0.250317 1.5007370654010714 1.499458