LOOPS
d p [ i ] [ j ] dp[i][j] dp[i][j]表示从 i , j i, j i,j到 r , c r, c r,c的期望,有 d p [ i ] [ j ] = p 0 × d p [ i ] [ j ] + p 1 × d p [ i ] [ j + 1 ] + p 2 × d p [ i + 1 ] [ j ] + 2 dp[i][j] = p_0 \times dp[i][j] + p_1 \times dp[i][j + 1] + p_2 \times dp[i + 1][j] + 2 dp[i][j]=p0×dp[i][j]+p1×dp[i][j+1]+p2×dp[i+1][j]+2
有 d p [ i ] [ j ] = ( p 1 × d p [ i ] [ j + 1 ] + p 2 × d p [ i + 1 ] [ j ] + 2 ) × 1 1 − p 0 dp[i][j] = (p_1 \times dp[i][j + 1] + p_2 \times dp[i + 1][j] + 2) \times \frac{1}{1 - p_0} dp[i][j]=(p1×dp[i][j+1]+p2×dp[i+1][j]+2)×1−p01,从后面开始转移。
#include <bits/stdc++.h> using namespace std; const double eps = 1e-7; const int N = 1e3 + 10; double dp[N][N], p[N][N][3]; int n, m; int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); while (scanf("%d %d", &n, &m) != EOF) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { for (int k = 0; k < 3; k++) { scanf("%lf", &p[i][j][k]); } } } memset(dp, 0, sizeof dp); for (int i = n; i >= 1; i--) { for (int j = m; j >= 1; j--) { dp[i][j] = (p[i][j][1] * dp[i][j + 1] + p[i][j][2] * dp[i + 1][j] + 2) / (1 - p[i][j][0]); } } printf("%.3f\n", dp[1][1]); } return 0; }
Aeroplane chess
类似上一题,但是就是要每次碰到能跳的位置要一直跳转到不能再跳为止。
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; double dp[N]; int a[N], n, m; int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); while (scanf("%d %d", &n, &m) && (n + m)) { memset(dp, 0, sizeof dp), memset(a, 0, sizeof a); for (int i = 1; i <= m; i++) { int x, y; scanf("%d %d", &x, &y); a[x] = y; } for (int i = n - 1; i >= 0; i--) { for (int j = 1; j <= 6; j++) { int cur = i + j; while (a[cur]) { cur = a[cur]; } dp[i] += (dp[cur] + 1) / 6.0; } } printf("%.4f\n", dp[0]); } return 0; }
One Person Game
容 易 推 出 : E i = ∑ p k E i + k + p 0 E 0 + 1 接 下 来 用 待 定 系 数 法 E 0 为 我 们 要 求 的 , 假 设 E i = a i E 0 + b i E i = ∑ p k ( a i + k E 0 + b i + k ) + p 0 E 0 + 1 E i = ( ∑ p k a i + k + p 0 ) E 0 + ∑ p k b i + k + 1 a i = ∑ p k a i + k + p 0 , b i = ∑ p k b i + k + 1 容易推出:E_i = \sum p_k E_{i + k} + p_0 E_0 + 1\\ 接下来用待定系数法\\ E_0为我们要求的,假设E_i = a_i E_0 + b_i\\ E_i = \sum p_k (a_{i + k} E_0 + b_{i + k}) + p_0 E_0 + 1\\ E_i = (\sum p_k a_{i + k} + p_0) E_0 + \sum p_k b_{i + k} + 1\\ a_i = \sum p_k a_{i + k} + p_0, b_i = \sum p_k b_{i + k} + 1\\ 容易推出:Ei=∑pkEi+k+p0E0+1接下来用待定系数法E0为我们要求的,假设Ei=aiE0+biEi=∑pk(ai+kE0+bi+k)+p0E0+1Ei=(∑pkai+k+p0)E0+∑pkbi+k+1ai=∑pkai+k+p0,bi=∑pkbi+k+1
#include <bits/stdc++.h> using namespace std; const int N = 510; double A[N], B[N], p[20]; int n, k1, k2, k3, a, b, c; int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); int T; scanf("%d", &T); while (T--) { scanf("%d %d %d %d %d %d %d", &n, &k1, &k2, &k3, &a, &b, &c); memset(A, 0, sizeof A), memset(B, 0, sizeof B), memset(p, 0, sizeof p); p[0] = 1.0 / (k1 * k2 * k3); for (int i = 1; i <= k1; i++) { for (int j = 1; j <= k2; j++) { for (int k = 1; k <= k3; k++) { if (i == a && j == b && k == c) { continue; } p[i + j + k] += p[0]; } } } for (int i = n; i >= 0; i--) { for (int j = 3; j <= k1 + k2 + k3; j++) { A[i] += p[j] * A[i + j]; B[i] += p[j] * B[i + j]; } A[i] += p[0]; B[i] += 1; } printf("%.15f\n", B[0] / (1 - A[0])); } return 0; }
Collecting Bugs
每次共有四种情况发生:
- 这个 b u g bug bug出现在已有的子系统里,并且在已有的 b u g bug bug里,概率为 i s × i n \frac{i}{s} \times \frac{i}{n} si×ni
- 这个 b u g bug bug出现在已有的子系统里,但是是一个从未出现的新 b u g bug bug,概率为 i s × n − i n \frac{i}{s} \times \frac{n - i}{n} si×nn−i
- 这个 b u g bug bug出现在新的子系统里,但是是一个已有的 b u g bug bug,概率为 s − i s × i n \frac{s - i}{s} \times \frac{i}{n} ss−i×ni
- 这个 b u g bug bug出现在新的子系统里,并且是一个新的 b u g bug bug,概率为 s − i s × n − i n \frac{s - i}{s} \times \frac{n - i}{n} ss−i×nn−i
综上:我们定义 d p [ i ] [ j ] dp[i][j] dp[i][j]表示已经在 i i i个子系统里出现过 j j j个 b u g bug bug,到在 s s s个子系统里出现过 n n n个 b u g bug bug的步数期望,
d p [ i ] [ j ] = i × j s × n d p [ i ] [ j ] + i × ( n − j ) s × n d p [ i ] [ j + 1 ] + ( s − i ) × j s × n d p [ i + 1 ] [ j ] + ( s − i ) × ( s − j ) s × n d p [ i + 1 ] [ j + 1 ] dp[i][j] = \frac{i \times j}{s \times n} dp[i][j] + \frac{i \times (n - j)}{s \times n}dp[i][j + 1] + \frac{(s - i) \times j}{s \times n}dp[i + 1][j] + \frac{(s - i) \times (s - j)}{s \times n} dp[i + 1][j + 1] dp[i][j]=s×ni×jdp[i][j]+s×ni×(n−j)dp[i][j+1]+s×n(s−i)×jdp[i+1][j]+s×n(s−i)×(s−j)dp[i+1][j+1]
#include <bits/stdc++.h> using namespace std; const int N = 1e3 + 10; double dp[N][N]; int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); int n, s; while (scanf("%d %d", &n, &s) != EOF) { memset(dp, 0, sizeof dp); for (int i = n; i >= 0; i--){ for (int j = s; j >= 0; j--){ if(i == n && j == s) { continue; } double factor = n * s - i * j; dp[i][j] = dp[i + 1][j] * j * (n - i) + dp[i][j + 1] * (s - j) * i + dp[i + 1][j + 1] * (n - i) *(s - j) + n * s; dp[i][j] /= factor; } } printf("%.4f\n", dp[0][0]); } return 0; }
Card Collector
容易想到 d p dp dp转移方程 d p [ i ] dp[i] dp[i]表示已经收集了 i i i张卡到收集 n n n张卡所需地步数期望,
d p [ i ] = ∑ p k × d p [ i + k ] + p 0 × d p [ i ] + 1 dp[i] = \sum p_{k} \times dp[i + k] + p_0 \times dp[i] + 1 dp[i]=∑pk×dp[i+k]+p0×dp[i]+1,
d p [ i ] = ∑ p k × d p [ i + k ] + 1 1 − p 0 dp[i] = \frac{\sum p_k \times dp[i + k] + 1} {1 - p_0} dp[i]=1−p0∑pk×dp[i+k]+1
p 0 + ∑ p k = 1 p_0 + \sum p_k = 1 p0+∑pk=1
然后逆向进行 d p dp dp即可。
#include <bits/stdc++.h> using namespace std; const int N = 25; double dp[1 << 21], p[N]; int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); int n; while (scanf("%d", &n) != EOF) { for (int i = 0; i < n; i++) { scanf("%lf", &p[i]); } memset(dp, 0, sizeof dp); for (int i = (1 << n) - 2; i >= 0; i--) { double delt = 0; for (int j = 0; j < n; j++) { if (i >> j & 1) { continue; } delt += p[j]; dp[i] += p[j] * dp[i | (1 << j)]; } dp[i] += 1; dp[i] /= delt; } printf("%.4f\n", dp[0]); } return 0; }
1765 谷歌的恐龙
在每一层我们的期望应该是 a 0 = n × ( n − 1 ) 2 a_0 = \frac{n \times (n - 1)}{2} a0=2n×(n−1),我们每一次有 q = n − m n q = \frac{n - m}{n} q=nn−m的概率继续游戏,
所以有如下 a 0 , a 0 × q , a 0 × q 2 , a 0 × a 3 , … , a n − 1 × q n − 1 , a n × a n a_0, a_0 \times q, a_0 \times q ^ 2, a_0 \times a ^ 3, \dots,a_{n - 1} \times q ^{n - 1}, a_{n} \times a ^{n} a0,a0×q,a0×q2,a0×a3,…,an−1×qn−1,an×an。
a 0 × 1 − q n 1 − q , n a_0 \times \frac{1 - q ^ n}{1 - q}, n a0×1−q1−qn,n趋于无穷大时, q n = 0 q ^ n = 0 qn=0,有 a 0 1 − q = a 0 m n = n 2 × ( n − 1 ) 2 × m \frac{a_0}{1 - q} = \frac{a_0}{\frac{m}{n}} = \frac{n ^ 2 \times (n - 1)}{2 \times m} 1−qa0=nma0=2×mn2×(n−1)。
所以期望为 n × ( n − 1 ) 2 × m \frac{n \times (n - 1)}{2 \times m} 2×mn×(n−1)。
#include <bits/stdc++.h> using namespace std; int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); double n, m; scanf("%lf %lf", &n, &m); printf("%.6f\n", n * (n - 1) / 2 / m); return 0; }
P4550 收集邮票
∑ i = 1 n = n 2 + n 2 所 以 我 们 分 别 求 出 n 2 , n 的 期 望 即 可 , f [ i ] 表 示 从 i 到 n , n 的 期 望 , g [ i ] 表 示 从 i 到 n , n 2 的 期 望 。 n 的 期 望 : f [ i ] = i n ( f [ i ] + 1 ) + n − i n ( f [ i + 1 ] + 1 ) n 2 的 期 望 g [ i ] = i n ( f [ i ] + 1 ) 2 + n − i n ( f [ i + 1 ] + 1 ) 2 f [ i ] 2 = g [ i ] , f [ i + 1 ] 2 = g [ i + 1 ] 化 简 有 : f [ i ] = f [ i + 1 ] + n n − i g [ i ] = g [ i + 1 ] + 2 f [ i + 1 ] + 2 i n − i f [ i ] + n n − i \sum_{i = 1} ^{n} = \frac{n ^ 2 + n}{2}\\ 所以我们分别求出n ^ 2, n的期望即可,f[i]表示从i 到n, n的期望,g[i] 表示从i 到n,n ^ 2的期望。\\ n的期望:\\ f[i] = \frac{i}{n}(f[i] + 1) + \frac{n - i}{n}(f[i + 1] + 1)\\ n ^ 2的期望\\ g[i] = \frac{i}{n}(f[i] + 1) ^ 2 + \frac{n - i}{n}(f[i + 1] + 1) ^ 2\\ f[i] ^ 2 = g[i], f[i + 1] ^ 2 = g[i + 1]\\ 化简有:f[i] = f[i + 1] + \frac{n}{n - i}\\ g[i] = g[i + 1] + 2f[i + 1] + 2\frac{i}{n - i}f[i] + \frac{n}{n - i}\\ i=1∑n=2n2+n所以我们分别求出n2,n的期望即可,f[i]表示从i到n,n的期望,g[i]表示从i到n,n2的期望。n的期望:f[i]=ni(f[i]+1)+nn−i(f[i+1]+1)n2的期望g[i]=ni(f[i]+1)2+nn−i(f[i+1]+1)2f[i]2=g[i],f[i+1]2=g[i+1]化简有:f[i]=f[i+1]+n−ing[i]=g[i+1]+2f[i+1]+2n−iif[i]+n−in
#include <bits/stdc++.h> using namespace std; const int N = 1e4 + 10; double f[N], g[N]; int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); int n; scanf("%d", &n); for (int i = n - 1; i >= 0; i--) { f[i] = f[i + 1] + 1.0 * n / (n - i); g[i] = g[i + 1] + 2 * f[i + 1] + 2.0 * i / (n - i) * f[i] + 1.0 * n / (n - i); } printf("%.2f\n", (f[0] + g[0]) / 2); return 0; }
P3802 小魔女帕琪
#include <bits/stdc++.h> using namespace std; int main() { // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); double a[7], sum = 0; for (int i = 0; i < 7; i++) { cin >> a[i]; sum += a[i]; } double ans = 1; for (int i = 0; i < 6; i++) { ans = ans * (i + 1) * a[i] / (sum - i); } ans *= a[6]; printf("%.3f\n", ans * 7.0); return 0; }