概率期望
LOOPS
dp[i][j]dp[i][j]dp[i][j]表示从i,ji, ji,j到r,cr, cr,c的期望,有dp[i][j]=p0×dp[i][j]+p1×dp[i][j+1]+p2×dp[i+1][j]+2dp[i][j] = p_0 \times dp[i][j] + p_1 \times dp[i][j + 1] + p_2 \times dp[i + 1][j] + 2dp[i][j]=p0×dp[i][j]+p1×dp[i][j+1]+p2×dp[i+1][j]+2
有dp[i][j]=(p1×dp[i][j+1]+p2×dp[i+1][j]+2)×11−p0dp[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
容易推出: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容易推出: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
每次共有四种情况发生:
- 这个bugbugbug出现在已有的子系统里,并且在已有的bugbugbug里,概率为is×in\frac{i}{s} \times \frac{i}{n}si×ni
- 这个bugbugbug出现在已有的子系统里,但是是一个从未出现的新bugbugbug,概率为is×n−in\frac{i}{s} \times \frac{n - i}{n}si×nn−i
- 这个bugbugbug出现在新的子系统里,但是是一个已有的bugbugbug,概率为s−is×in\frac{s - i}{s} \times \frac{i}{n}ss−i×ni
- 这个bugbugbug出现在新的子系统里,并且是一个新的bugbugbug,概率为s−is×n−in\frac{s - i}{s} \times \frac{n - i}{n}ss−i×nn−i
综上:我们定义dp[i][j]dp[i][j]dp[i][j]表示已经在iii个子系统里出现过jjj个bugbugbug,到在sss个子系统里出现过nnn个bugbugbug的步数期望,
dp[i][j]=i×js×ndp[i][j]+i×(n−j)s×ndp[i][j+1]+(s−i)×js×ndp[i+1][j]+(s−i)×(s−j)s×ndp[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
容易想到dpdpdp转移方程dp[i]dp[i]dp[i]表示已经收集了iii张卡到收集nnn张卡所需地步数期望,
dp[i]=∑pk×dp[i+k]+p0×dp[i]+1dp[i] = \sum p_{k} \times dp[i + k] + p_0 \times dp[i] + 1dp[i]=∑pk×dp[i+k]+p0×dp[i]+1,
dp[i]=∑pk×dp[i+k]+11−p0dp[i] = \frac{\sum p_k \times dp[i + k] + 1} {1 - p_0}dp[i]=1−p0∑pk×dp[i+k]+1
p0+∑pk=1p_0 + \sum p_k = 1p0+∑pk=1
然后逆向进行dpdpdp即可。
#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 谷歌的恐龙
在每一层我们的期望应该是a0=n×(n−1)2a_0 = \frac{n \times (n - 1)}{2}a0=2n×(n−1),我们每一次有q=n−mnq = \frac{n - m}{n}q=nn−m的概率继续游戏,
所以有如下a0,a0×q,a0×q2,a0×a3,…,an−1×qn−1,an×ana_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。
a0×1−qn1−q,na_0 \times \frac{1 - q ^ n}{1 - q}, na0×1−q1−qn,n趋于无穷大时,qn=0q ^ n = 0qn=0,有a01−q=a0mn=n2×(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=1n=n2+n2所以我们分别求出n2,n的期望即可,f[i]表示从i到n,n的期望,g[i]表示从i到n,n2的期望。n的期望:f[i]=in(f[i]+1)+n−in(f[i+1]+1)n2的期望g[i]=in(f[i]+1)2+n−in(f[i+1]+1)2f[i]2=g[i],f[i+1]2=g[i+1]化简有:f[i]=f[i+1]+nn−ig[i]=g[i+1]+2f[i+1]+2in−if[i]+nn−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;
}