本题解所有内容转自 HDU4624 Endless Spin(概率&&dp) - chanme - 博客园。
容斥。 涉及到一个神奇的转化。
- 首先要做的是一个题目的转化。如果我定义pi为 恰好i次将区间涂黑的概率,那么显然期望
E
=
0
p
0
+
1
p
1
+
2
p
2
+
⋯
E= 0p_0+1p_1+2p_2+\cdots
E=0p0+1p1+2p2+⋯ 换一种角度看这个公式,其实这个公式可以这么写
E = p 1 + p 2 + p 3 + p 4 + p 5 + ⋯ + p 2 + p 3 + p 4 + p 5 + ⋯ + p 3 + p 4 + p 5 + ⋯ E = p1 + p2 + p3 + p4 + p5 + \cdots \\ + p2 + p3 + p4 + p5 + \cdots \\ + p3 + p4 + p5 + \cdots E=p1+p2+p3+p4+p5+⋯+p2+p3+p4+p5+⋯+p3+p4+p5+⋯
定义 L i = p i + 1 + p i + 2 + ⋯ L_i=p_{i+1} + p_{i+2} + \cdots Li=pi+1+pi+2+⋯ 那么我们可以把Li理解成覆盖了i次都没有将整个区间涂黑的概率。
所以 E = L 0 + L 1 + L 2 + ⋯ E=L_0 +L_1 +L_2+\cdots E=L0+L1+L2+⋯ - 理解了上面这一点之后我们可以先考虑一种暴力的做法,那就是枚举 2 n 2^n 2n 个最后留下来的点,譬如最后留下来的点是 v 1 , v 2 , v 3 ⋯ v k v_1,v_2,v_3 \cdots v_k v1,v2,v3⋯vk,那么实际上可选的区间只有 [ 1 , v 1 − 1 ] , [ v 1 + 1 , v 2 − 1 ] , [ v 2 + 1 , v 3 − 1 ] ⋯ [1,v_1-1],[v_1+1,v_2-1],[v_2+1,v_3-1]\cdots [1,v1−1],[v1+1,v2−1],[v2+1,v3−1]⋯ 那么这里区间的选法就有 A A A 种( A A A 是可以求出来的),要使这些点都能被留下来,那么我们每次选的只能是这 A A A 个区间,因而概率 p = A n ( n + 1 ) / 2 p = \dfrac A{n(n+1)/2} p=n(n+1)/2A. 那么对于 L i L_i Li 来说 L i + = p i ∗ ( − 1 ) k - 1 L_i += p^i* (-1)^{k-1} Li+=pi∗(−1)k-1. 之所以要乘 ( − 1 ) k (-1)^k (−1)k 是因为这里需要有一个容斥。考虑到 p i p^i pi 的累加和即 p + p 1 + p 2 + ⋯ = 1 1 − p p+p^1 +p^2 +\cdots = \dfrac 1{1-p} p+p1+p2+⋯=1−p1 所以对于每个 2 n 2^n 2n,它对最后期望的影响实际上是 1 1 − p ⋅ ( − 1 ) k − 1 \dfrac1{1-p}\cdot(-1)^{k-1} 1−p1⋅(−1)k−1.
- 暴力的想法给到了,那么下面就是要优化一下这种做法了,因为我总不可能
2
50
2^{50}
250 枚举所有剩下的点。一个自然的想法是考虑 DP,看上面的式子我们不难发现实际上最后起作用的是
A
A
A 和
k
k
k 的奇偶性,而
A
A
A 的范围是有限的(总的区间个数),那么我们可以定义一个状态
d
p
[
i
]
[
j
]
[
k
]
dp[i][j][k]
dp[i][j][k] 表示,第
i
i
i 个点是白点(未被覆盖),且前
i
i
i 个白点的奇偶性为
j
j
j,可选区间的个数为
k
k
k 有多少个子集。 那么对于一个期望值
E
n
(
n
≥
i
)
E_n(n\ge i)
En(n≥i) 来说这个状态对
E
n
E_n
En 的影响实际上是
可选的区间 A = A = A= 前i个点的可选区间数 + [ i . . n ] + [i..n] +[i..n]这一段为黑的可选区间数 = k + ( n − i + 1 ) ( n − i ) 2 = k+\dfrac{(n-i+1)(n-i)}2 =k+2(n−i+1)(n−i);
p = A n ( n + 1 ) / 2 E n + = d p [ i ] [ j ] [ k ] ⋅ ( 1 − p ) ∗ ( − 1 ) j − 1 p = \dfrac A{n(n+1)/2} \\E_n += dp[i][j][k]\cdot(1-p)*(-1)^{j-1} p=n(n+1)/2AEn+=dp[i][j][k]⋅(1−p)∗(−1)j−1
核心代码,亦转自原作者。
dp[0][0][0] = 1;
for (int i = 0; i <= 50; ++i)
for (int j = 0; j <= (i + 1)*i / 2; ++j) {
if (dp[i][0][j])
for (int k = i + 1; k <= 50; ++k)
dp[k][1][j + (k - i)*(k - i - 1) / 2] += dp[i][0][j];
if (dp[i][1][j])
for (int k = i + 1; k <= 50; ++k)
dp[k][0][j + (k - i)*(k - i-1) / 2] += dp[i][1][j];
}
for (int i = 1; i <= 50; ++i)
for (int k = 0; k <= i; ++k)
for (int j = 0; j <= (k + 1)*k / 2; ++j) {
if (dp[k][0][j]) {
long double p = (j + (i - k + 1)*(i - k) / 2 + .0) / ((i + 1)*i / 2);
if (p == 1.0) continue;
E[i] -= dp[k][0][j] / (1 - p);
}
if (dp[k][1][j]){
long double p = (j + (i - k + 1)*(i - k) / 2 + .0) / ((i + 1)*i / 2);
if (p == 1.0) { continue; }
E[i] += dp[k][1][j] / (1 - p);
}
}
为防止老实人纠正,此处的 Spin 应理解为“纺纱”而非“自转”。 ↩︎