kuangbin 带你飞 概率期望
正推不行就逆推!
经典问题:生日悖论
换成其互斥事件:m个人, 每个人生日都不相同的概率 ≤ 0.5 时最小人数。
这就是邮票收集问题的变形:每个邮票至少出现一次的概率 小于等于 0.5
邮票收集问题资料:https://en.wikipedia.org/wiki/Coupon_collector%27s_problem
我们现在面对的是一个n面的骰子, 骰子的每面都是随机出现的, 求问将所有面都被看完所期望的投掷次数(假设只看最上面那一面)
那么, 问题的解就是:
H[n] = (1 + 1/2 + 1/3 + 1/4 + ... + 1/n), 这就是调和级数的前n项。
这个值近似等于欧拉常数约为:0.57721566490153286060651209。(不过这是一个当n接近无穷时的近似值, 并不能代替具体的H[n], 比如当 n = 1 || 2时)
而所求的是期望的权值, 根据期望的线性性质E(XY) = E(X)*E(Y)
所以, 总的权值期望就等价于 每次的权值期望 * 次数的期望。
n个面, 每个面至少出现一次的期望次数是:E(x) = n * H[n],那么, 某个指定的面至少出现一次的期望次数就是E(z) = E(x)/n = H[n]。
Light Oj 1027 A Dangerous Maze
题意 : 在n个门前选择一扇门出去, 然后如果第i扇门的 Xi值是正的话,你会花费Xi时间后出去 , 如果Xi是负数的话你会花费-Xi时间后回到老地方,并且忘记了刚才的选择, 选择一扇门的概率是等概的。求出去的期望。
思路 :定义一次选择选择到Xi是整数的概率为P1,选择到负数的概率是P2,然后选择了正数后平均在T1时间后出去, 选择了负数后平均在T2时间后回到原地。接着设出去的期望是Y,那么可以写出一个式子 :Y = P1 * T1 + P2 * (T2 + Y), 这样的话问题就得到了解决, 最后整理下式子就是 : Y = 正数个数的倒数 * ∑abs(Xi) ;
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
LL gcd(LL a, LL b) {return a % b == ? b : gcd(b, a % b);}
LL tot,sum; int main() {
int T,kase = ;
scanf("%d",&T);
while (T--) {
tot = ;
sum = ;
int N;
scanf("%d",&N);
for (int i = ; i <= N ; i++) {
int x;
scanf("%d",&x);
if (x > ) tot++;
sum += abs(x);
}
if (tot == ) printf("Case %d: inf\n",kase++);
else {
LL g = gcd(sum,tot);
printf("Case %d: %lld/%lld\n",kase++,sum / g,tot / g);
}
}
return ;
}
LightOj 1030 Discovering Gold
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
LL gcd(LL a, LL b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
double dp[MAXN],val[MAXN];
int main() {
int T,kase = ;
cin >> T;
while (T--) {
memset(dp,,sizeof(dp));
int N;
cin >> N;
for (int i = ; i <= N ; i++) cin >> val[i];
dp[N] = val[N];
for (int i = N - ; i >= ; i--) {
dp[i] = val[i];
double cnt = min(6.0,1.0 * (N - i));
for (int j = ; j <= cnt ; j++)
dp[i] += dp[i + j] * 1.0 / cnt;
}
printf("Case %d: %.8lf\n",kase++,dp[]);
}
return ;
}
LightOj 1038 Race to 1 Again
比较简单枚举因子就可以了
dp[x] = (dp[fac1] + 1) / cnt + (dp[fac2] +1)/ cnt + (dp[x] + 1) / cnt
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
vector<int>res[MAXN];
double dp[MAXN]; void init() {
for (int i = ; i < MAXN ; i++) res[i].clear();
for (int i = ; i < MAXN ; i++) {
for (int j = i ; j < MAXN ; j += i)
res[j].push_back(i);
}
} double calcu(int x) {
if (x == ) return 0.0;
else if (dp[x] >= ) return dp[x];
int tot = res[x].size();
double ans = 1.0 * tot;
for (int i = ; i < tot - ; i++) {
ans += calcu(res[x][i]);
}
return dp[x] = ans / (tot - 1.0);
} int main() {
init();
memset(dp,-,sizeof(dp));
int T,kase = ;
scanf("%d",&T);
while (T--) {
int N;
scanf("%d",&N);
double ret = calcu(N);
printf("Case %d: %.8lf\n",kase++,ret);
}
return ;
}
LightOj 1079 Just another Robbery
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const double INF = 1e10;
int N,M;
double P;
struct node {
double p;
int val;
}src[MAXN];
double dp[MAXN][MAXN * MAXN]; int main() {
int T,kase = ;
scanf("%d",&T);
while (T--) {
scanf("%lf%d",&P,&N);
for (int i = ; i <= N ; i++) scanf("%d%lf",&src[i].val,&src[i].p);
for (int i = ; i < MAXN ; i++)
for (int j = ; j < MAXN * MAXN ; j++) dp[i][j] = INF;
dp[][] = ;
for (int i = ; i <= N ; i++) {
for (int j = ; j < MAXN * MAXN ; j++) {
dp[i][j] = min(dp[i - ][j],dp[i][j]);
if (j >= src[i].val && dp[i - ][j - src[i].val] < INF) {
dp[i][j] = min(dp[i][j],dp[i - ][j - src[i].val] + ( - dp[i - ][j - src[i].val]) * src[i].p);
//printf("dp[%d][%d] = %lf\n",i,j,dp[i][j]);
}
}
}
int ret = ;
for (int i = MAXN * MAXN - ; i >= ; i--) {
if (dp[N][i] <= P) {
printf("Case %d: %d\n",kase++,i);
break;
}
}
}
return ;
}
LightOj 1104 Birthday Paradox
题意:
若一年有n天, 问至少需要多少个人才能满足其中两个人生日相同的概率大于等于0.5?
思路:
经典问题:生日悖论
换成其互斥事件:m个人, 每个人生日都不相同的概率 ≤ 0.5 时最小人数。
这就是邮票收集问题的变形:每个邮票至少出现一次的概率 小于等于 0.5
等价于:
找到最小的n, 使得:H[n] = (n / n * (n - 1) / n * (n - 2) / n * ... * (n - i) / n) <= 0.5
就是求所有人生日都不同的概率小于等于0.5(那么至少两个人同一天就是大于等于0,5);
加入一年365天.那么10个人全都不同天生日的概率就是
366/366 * 365/366 * 364/366 .... * 356/366;
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std; int n;
int main() {
int t;
int cas = ;
scanf("%d",&t);
while(t--) {
scanf("%d",&n);
double res = ;
int i;
for(i = n - ; i >= ; i--) {
double tmp = i;
res *= (tmp / n);
if(res <= 0.5)
break;
}
printf("Case %d: %d\n",cas++, n - i);
}
}
LightOj 1151 Snakes and Ladders
复制一波题解:
dp[i] 表示 在格子i时,结束游戏需要抛掷骰子的次数
当i处有snake或者ladders时
dp[i]=dp[go[i]]
否则
dp[i]=dp[a1]+dp[a2]+...+dp[an]+6cnt
因为题目中的一句话,如果抛骰子然后出界的话,需要重新再抛掷,所以转移到的位置个数不是6个,但是代价一定是6个(除a1->an以外的点被忽略掉,但是骰子还是抛掷了,所以次数还是要加上去)
发现方程中存在环,所以用高斯消元来解方程
必然存在环的。由于传送的特殊形式
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const double eps = 1e-;
int pos[MAXN]; struct Matrix {
int equ,var;
double mat[MAXN][MAXN];
double x[MAXN]; void build() {
memset(mat,,sizeof(mat));
memset(x,,sizeof(x));
mat[][] = ; x[] = ;
for (int i = ; i < ; i++) {
if (pos[i] == i) {
int cnt = ;
for (int j = ; j <= ; j++) {
if (i + j <= ) {
cnt++;
mat[i][i + j] = -;
}
}
mat[i][i] = 1.0 * cnt;
x[i] = 6.0;
}
else {
x[i] = ;
mat[i][i] = ;
mat[i][pos[i]] = -;
}
}
equ = var = ;
} int gauss() {
int i,j,k,col,max_r;
for (k = ,col = ; k < equ && col < var ; k++,col++) {
max_r = k;
for (i = k + ; i < equ ; i++) if (fabs(mat[i][col]) > fabs(mat[max_r][col])) max_r = i;
if (fabs(mat[max_r][col]) < eps) continue;
if (k != max_r) {
for (j = col ; j < var ; j++) swap(mat[k][j],mat[max_r][j]);
swap(x[k],x[max_r]);
}
x[k] /= mat[k][col];
for (j = col + ; j < var ; j++) mat[k][j] /= mat[k][col];
mat[k][col] = ;
for (int i = ; i < equ ; i++) {
if (i != k) {
x[i] -= x[k] * mat[i][k];
for (j = col + ; j < var ; j++) mat[i][j] -= mat[k][j] * mat[i][col];
mat[i][col] = ;
}
}
}
return ;
} }slover; int main() {
int T,kase = ;
scanf("%d",&T);
while (T--) {
for (int i = ; i <= ; i++) pos[i] = i;
int N;
scanf("%d",&N);
for (int i = ; i <= N ; i++) {
int u,v;
scanf("%d%d",&u,&v);
pos[u] = v;
}
slover.build();
slover.gauss();
printf("Case %d: %.12lf\n",kase++,slover.x[]);
}
return ;
}
LightOj 1248 Dice (III)
思路:设dp[i]为已经扔出了i个不同面值,还要扔dp[i]次才能扔出n个不同面的期望次数,显然dp[n] = 0,要求dp[0]
则dp[i] = 1+ i/n * dp[i] + (n-i)/n * dp[i+1],本来要扔的一次加上各个状态转移的期望值
=>dp[i] = n / (n-i) + dp[i+1]
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const double eps = 1e-;
double dp[MAXN];
int main() {
int kase = ,T;
cin >> T;
while (T--) {
int n;
cin >> n;
dp[] = ;
for (int i = ; i < n ; i++)
dp[i + ] = dp[i] + 1.0 * n / (double)(n - i);
printf("Case %d: %.8lf\n",kase++,dp[n]);
}
return ;
}
LightOj 1265 Island of Survival
在孤岛生存, 孤岛上有t头老虎,d头鹿, 每天会出现随机出现两只生物(包括你自己), 如果出现了一只老虎,那么你将被吃掉, 如果两只老虎, 则两只老虎会同归于尽,其他情况你都将生存下来。
当孤岛上没有老虎时, 就视为你生存成功。
问你生存成功的最大概率。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
double dp[MAXN][MAXN];
int main() {
int T,kase = ;
scanf("%d",&T);
while (T--) {
int t,d;
scanf("%d%d",&t,&d);
for (int i = ; i <= t ; i++)
for (int j = ; j <= d ; j++) dp[i][j] = 0.0;
for (int i = ; i <= d ; i++) dp[][i] = 1.0;
for (int i = ; i <= t ; i++) {
for (int j = ; j <= d ; j++) {
double r1 = ,r2 = ;
int tot = i + j + ;
if (i >= ) r1 += dp[i - ][j] * (double)(i * i - i) / (double)(tot * tot - tot);
if (j >= ) r1 += dp[i][j - ] * (double)( * i * j) / (double)(tot * tot - tot);
double p = 0.0;
if (j >= ) p = (double)(j * j - j) / (double)(tot * tot - tot);
if (j >= ) {
r2 = r1;
r2 += dp[i][j - ] * (double)(j * ) / (double)(tot * tot - tot);
r2 /= ( - p);
}
r1 /= ( - p - (double)(j * ) / (double)(tot * tot - tot));
dp[i][j] = max(r1,r2);
}
}
printf("Case %d: %.12f\n", kase++, dp[t][d]);
}
return ;
}
LightOj 1274 Beating the Dataset
给一个文档, 这个文档由yes 、no 组成, 共有s个byte, 共有n个yes、no。
假设yes的个数为yes_num, no的个数为no_num。
将这n个数进行排列, 对于每个排列, 将其右移一个结果, 并在最左端补上yes, 再将其与原排列进行对比, 看有多少个不同的。
计算所有排列中 不同结果的平均次数。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
int N,S;
double dp[][MAXN][]; int main() {
int T,kase = ;
scanf("%d",&T);
while (T--) {
scanf("%d%d",&N,&S);
int right = S - * N;
int wa = * N - S;
memset(dp,,sizeof(dp));
int cur = ;
for (int i = ; i <= N ; i++) {
int nxt = cur ^ ;
for (int j = ; j <= min(right,i) ; j++) {
double p1 = (double)j / i;
double p2 = 1.0 - p1;
if (j >= ) {
dp[nxt][j][] = (dp[cur][j][] + 1.0) * p2 + dp[cur][j - ][] * p1;
dp[nxt][j][] = (dp[cur][j - ][] + 1.0) * p1 + dp[cur][j][] * p2;
}
else {
dp[nxt][j][] = (dp[cur][j][] + )* p2;
dp[nxt][j][] = dp[cur][j][] * p1;
}
}
cur = nxt;
}
printf("Case %d: %.8lf\n",kase++,dp[cur][right][]);
}
return ;
}
给一个X * Y * Z 的立方体, 每个单位立方体内都有一盏灯, 初始状态是灭的, 你每次操作如下:
1)选择一个点(x1, y1, z1)
再选择一个点(x2, y2, z2)
将这两个点所形成的立方体内所有的灯全部转换状态(灭的变亮的, 亮的变灭的)
问, K次操作后, 亮着的灯的期望数目。
三维坐标系, 每个维度都是相互独立的, 所以可以分开计算再相乘。
考虑x轴, 对于每个点, 被选中的概率是多少:假设这个点左边有a个点,右边有b个点,
那么这个点不被选中的概率是p = 1.0 - ((x - 1) * (x - 1) - (a * a + b * b)) / x * x。
则,这个点在K次操作后被点亮的期望为:E = sigma C(k, i) * p * (1 - p) ^ (k - i),i为奇数, 因为i为偶数时灯是灭的。
这是二项展开式(p + (1 - p)) ^ k 的所有奇数项。
因此, E = ((p + (1 - p)) ^ k - (-p + (1 - p)) ^ k) / 2, 蓝色部分将所有的奇数项变成了负数, 偶数项不变, 相减后则成了两倍的奇数项之和。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
int X,Y,Z,K;
double calcu(int x,int n) {
return 1.0 - ((x - ) * (x - ) * 1.0 + (n - x) * (n - x) * 1.0) * 1.0 / (n * n);
} int main() {
int T,kase = ;
scanf("%d",&T);
while (T--) {
double ans = 0.0;
scanf("%d%d%d%d",&X,&Y,&Z,&K);
for (int i = ; i <= X ; i++) {
for (int j = ; j <= Y ; j++) {
for (int k = ; k <= Z ; k++) {
double p = calcu(i,X) * calcu(j,Y) * calcu(k,Z);
ans += (1.0 - pow( - 2.0 * p,K)) / 2.0;
}
}
}
printf("Case %d: %.8lf\n",kase++,ans);
}
return ;
}
LightOj 1287 Where to Run
题意:
有n个街口和m条街道, 你后边跟着警察,你需要进行大逃亡(又是大爱的抢银行啊),在每个街口你都有≥1个选择,
1)停留在原地5分钟。
2)如果这个街口可以到xi这个街口, 并且, 通过xi可以遍历完所有未走过的街口,那么就加入选择。
每个选择都是等概率的。
求警察抓住你所用时间的期望, 即你无路可走时的时间期望。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
int N,M;
const double INF = 1e14;
double G[][];
double dp[][ << ];
bool vis[][ << ]; bool calcu(int u,int sta) {
if (sta == ( << N) - ) {
dp[u][sta] = ;
return true;
}
if (vis[u][sta]) return dp[u][sta] > ;
vis[u][sta] = true;
dp[u][sta] = ;
int tot = ;
for (int i = ; i <= N ; i++) {
if( ((sta & ( << i)) == ) && G[u][i] < INF && calcu(i,sta | ( << i)) ) {
int nxtsta = sta | ( << i);
tot++;
dp[u][sta] += G[u][i] + dp[i][sta | ( << i)];
}
}
if (tot == ) {
dp[u][sta] = ;
return false;
}
dp[u][sta] /= (double)tot;
return true;
} int main() {
int T,kase = ;
scanf("%d",&T);
while (T--) {
memset(dp,-,sizeof(dp));
memset(vis,false,sizeof(vis));
for (int i = ; i < ; i++) for (int j = ; j < ; j++) G[i][j] = INF;
scanf("%d%d",&N,&M);
for (int i = ; i < M ; i++) {
int u,v; double w;
scanf("%d%d%lf",&u,&v,&w);
G[u][v] = G[v][u] = w;
}
calcu(,);
printf("Case %d: %.8lf\n",kase++,dp[][]);
}
return ;
}
LightOJ 1317
有N个人, M个篮框, 每个人投进球的概率是P。
问每个人投K次后, 进球数的期望。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
double ans,p;
int C[][];
int N,K; double calcu(int num) {
double ret = 1.0;
for (int i = ; i <= num ; i++) ret *= p;
for (int i = ; i <= N - num ; i++) ret *= ( - p);
return ret * num * C[N][num];
} int main() {
int T,kase = ;
C[][] = ;
C[][] = C[][] = ;
for (int i = ; i < ; i++) {
C[i][] = C[i][i] = ;
for (int j = ; j < i ; j++)
C[i][j] = C[i - ][j] + C[i - ][j - ];
}
//printf("%d\n",C[8][3]);
scanf("%d",&T);
while (T--) {
scanf("%d%*d%d%lf",&N,&K,&p);
double ret = 0.0;
for (int i = ; i <= N ; i++)
ret += calcu(i);
printf("Case %d: %.8lf\n",kase++,ret * K);
}
return ;
}
LightOj 1321 Sending Packets
题意:
给一个数据大小为S的数据包, 每一次发送需要K秒(单向),现在要从节点0 发送到节点 n-1。
其中有n - 1条路径, 每条路径都有一个传输成功率。
问传输成功所需最小时间的期望。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
double dp[MAXN][MAXN];
int N,M,S,K; void calcu(int kase) {
// memset(dp,0,sizeof(dp));
for (int i = ; i <= N ; i++) dp[i][i] = ;
for (int k = ; k < N ; k++) {
for (int i = ; i < N ; i++) {
for (int j = ; j < N ; j++)
dp[i][j] = max(dp[i][j],dp[i][k] * dp[k][j]);
}
}
double ans = dp[][N - ];
ans = 1.0 / ans * 2.0 * K * S;
printf("Case %d: %.8lf\n",kase++,ans);
} int main() {
int T,kase = ;
scanf("%d",&T);
while (T--) {
scanf("%d%d%d%d",&N,&M,&S,&K);
memset(dp,,sizeof(dp));
for (int i = ; i < M ; i++) {
int u,v;
double p;
scanf("%d%d%lf",&u,&v,&p);
dp[u][v] = dp[v][u] = max(dp[u][v],p / 100.0);
}
calcu(kase++);
}
return ;
}
LightOj 1342 Aladdin and the Magical Sticks
题意:
地上有n种棍子, 其中有两种类型, 一种类型是可识别, 一种类型是不可识别, 每个棍子都有一个权值。
当你捡到可识别的, 那么你以后就不会再捡这个棍子, 如果是不可识别的, 那么你有可能还会捡。
问将所有棍子收集完的权值的期望。
我们现在面对的是一个n面的骰子, 骰子的每面都是随机出现的(相当于是不可识别的棍子), 求问将所有面都被看完所期望的投掷次数(假设只看最上面那一面)
那么, 问题的解就是:
H[n] = (1 + 1/2 + 1/3 + 1/4 + ... + 1/n), 这就是调和级数的前n项。
这个值近似等于欧拉常数约为:0.57721566490153286060651209。(不过这是一个当n接近无穷时的近似值, 并不能代替具体的H[n], 比如当 n = 1 || 2时)
而所求的是期望的权值, 根据期望的线性性质E(XY) = E(X)*E(Y)
所以, 总的权值期望就等价于 每次的权值期望 * 次数的期望。
n个面, 每个面至少出现一次的期望次数是:E(x) = n * H[n],那么, 某个指定的面至少出现一次的期望次数就是E(z) = E(x)/n = H[n]。
因此, 假设这n个棍子都是不可识别的时候所期望的权值为:
Ea = E(w) * E(x), E(w)为权值的期望 = 权值的平均值。
但是, 这n个棍子里还有一些是可以识别的, 因此还要减去多余的期望。
先来计算一下可识别的棍子所需要的期望的次数, 这个答案为1。
当有六个球在箱子里, 采用不放回抽样, 你将六个球抽出来所期望的次数是多少?这是一个固定的值, 为6。
因此, 每个棍子多出来的部分就是(H[n] - 1) * w[i]。w[i]为某个可识别的棍子的权值。
设, 所有棍子的权值平均值为Wn
假设有k个可识别的棍子, 其权值平均值为Wk
So , 答案为: Ea - Eb = Wn * n * H[n] - k * Wk * (H[n] - 1)
化简: E = (Wn * n - k * Wk) * H[n] + k * Wk。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = ;
int n;
double h[MAXN];
void init()
{
h[] = ;
for(int i = ; i < MAXN; i ++)
h[i] = h[i - ] + 1.0 / i;
} int main()
{
int T;
int kcase = ;
init();
scanf("%d", &T);
while(T --)
{
scanf("%d", &n);
int a, b;
double ans = ;
for(int i = ; i < n; i ++)
{
scanf("%d %d", &a, &b);
ans += a * (b == ? : h[n]);
}
printf("Case %d: %.5lf\n", ++ kcase, ans);
}
return ;
}
LightOJ 1364
状压一下混子能充当的牌然后DP
#include<bits/stdc++.h>
using namespace std;
const int MAXN = ;
const int MAXM = ;
double dp[MAXN][MAXN][MAXN][MAXN][MAXM];
int bit[];
int C,D,H,S; bool decode(int a,int b,int c,int d,int sta) {
memset(bit,,sizeof(bit));
// printf("%d %d %d %d %d \n",a,b,c,d,sta);
int len = ;
while (sta) {
bit[len++] = sta % ;
sta /= ;
}
a += bit[];
b += bit[];
c += bit[];
d += bit[];
// printf("%d %d %d %d\n",a,b,c,d); scanf("%*d");
if (a >= C && b >= D && c >= H && d >= S) return true;
return false;
} double calcu(int a,int b,int c,int d,int sta) {
double &ans = dp[a][b][c][d][sta];
if (ans != -1.0) return ans;
if (decode(a,b,c,d,sta) == true) return ans = 0.0;
int tmp = sta;
ans = ;
int len = ,tot = ;
int bit[];
memset(bit,,sizeof(bit));
while (tmp) {
bit[len++] = tmp % ;
tmp /= ;
}
for (int i = ; i < ; i++) tot += bit[i];
int all = - a - b - c - d - tot;
if (a < && all > ) {
double p = ( - a) * 1.0 / all;
ans += (calcu(a + ,b,c,d,sta) + ) * p;
}
if (b < && all > ) {
double p = ( - b) * 1.0 / all;
ans += (calcu(a,b + ,c,d,sta)+ ) * p;
}
if (c < && all > ) {
double p = ( - c) * 1.0 / all;
ans += (calcu(a,b,c + ,d,sta) + ) * p;
}
if (d < && all > ) {
double p = ( - d) * 1.0 / all;
ans += (calcu(a,b,c,d + ,sta) + ) * p;
}
int nxt;
double val;
if (tot < && all > ) {
double p = ( - tot) * 1.0 / all;
nxt = (bit[] + ) + bit[] * + bit[] * + bit[] * ;
val = calcu(a,b,c,d,nxt);
nxt = bit[] + (bit[] + ) * + bit[] * + bit[] * ;
val = min(val,calcu(a,b,c,d,nxt));
nxt = bit[] + bit[] * + (bit[] + ) * + bit[] * ;
val = min(val,calcu(a,b,c,d,nxt));
nxt = bit[] + bit[] * + bit[] * + (bit[] + ) * ;
val = min(val,calcu(a,b,c,d,nxt));
ans += p * (val + );
}
return ans;
} int main() {
int T,kase = ;
scanf("%d",&T);
while (T--) {
scanf("%d%d%d%d",&C,&D,&H,&S);
for (int i = ; i < MAXN ; i++) for (int j = ; j < MAXN ; j++) for (int k = ; k < MAXN ; k++) for (int p = ; p < MAXN ; p++)
for (int q = ; q < MAXM ; q++) dp[i][j][k][p][q] = -1.0;
int cnt = ;
if (C > ) cnt += C - ; if (D > ) cnt += D - ;
if (H > ) cnt += H - ; if (S > ) cnt += S - ;
if (cnt > ) printf("Case %d: -1\n",kase++);
else printf("Case %d: %.8lf\n",kase++,calcu(,,,,));
}
return ;
}
kuangbin 带你飞 概率期望的更多相关文章
- KUANGBIN带你飞
KUANGBIN带你飞 全专题整理 https://www.cnblogs.com/slzk/articles/7402292.html 专题一 简单搜索 POJ 1321 棋盘问题 //201 ...
- [kuangbin带你飞]专题1-23题目清单总结
[kuangbin带你飞]专题1-23 专题一 简单搜索 POJ 1321 棋盘问题POJ 2251 Dungeon MasterPOJ 3278 Catch That CowPOJ 3279 Fli ...
- 「kuangbin带你飞」专题二十 斜率DP
layout: post title: 「kuangbin带你飞」专题二十 斜率DP author: "luowentaoaa" catalog: true tags: mathj ...
- 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开
[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...
- Tarjan 联通图 Kuangbin 带你飞 联通图题目及部分联通图题目
Tarjan算法就不说了 想学看这 https://www.byvoid.com/blog/scc-tarjan/ https://www.byvoid.com/blog/biconnect/ 下面是 ...
- 「kuangbin带你飞」专题十四 数论基础
layout: post title: 「kuangbin带你飞」专题十四 数论基础 author: "luowentaoaa" catalog: true tags: mathj ...
- 「kuangbin带你飞」专题二十二 区间DP
layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...
- 「kuangbin带你飞」专题十九 矩阵
layout: post title: 「kuangbin带你飞」专题十九 矩阵 author: "luowentaoaa" catalog: true tags: mathjax ...
- 「kuangbin带你飞」专题十八 后缀数组
layout: post title: 「kuangbin带你飞」专题十八 后缀数组 author: "luowentaoaa" catalog: true tags: - kua ...
随机推荐
- IDEA + Maven + SSM 框架整合步骤
因为前段时间自己想写个SSM的demo,然而不知怎么回事,配置完之后出现错误,怎么都调不好.最后从朋友那里拷了一个SSM的demo过来搭建成功,写这篇东西也是为了以后如果还有需要可以方便的查阅,并且也 ...
- Dijkstra标准模板
Dijkstra求最短路问题:单元求最短路,从任意点出发求得该点到达其他任意点的距离 Dijkstra其实是一种贪心策略,与出发点(即源点)所连接的点中找到距离最短的点(这个距离是源点到这个点的最短距 ...
- Markdown常用的几种语法
在VScode上面写的,现将代码粘贴如下:(在VScode里运行下即可) # Markdown语法 # Ctrl + k v 打开侧边预览 ## 一.加粗斜体删除线 **这是要加粗的文字** *这是要 ...
- octomap建立
1.安装ros的octomap ---已完成 2.阅读相关论文,了解其机理,并编写程序实现. 参考网页:https://www.cnblogs.com/gaoxiang12/p/5041142.ht ...
- MATLAB中矢量场图的绘制 (quiver/quiver3/dfield/pplane) Plot the vector field with MATLAB
1.quiver函数 一般用于绘制二维矢量场图,函数调用方法如下: quiver(x,y,u,v) 该函数展示了点(x,y)对应的的矢量(u,v).其中,x的长度要求等于u.v的列数,y的长度要求等于 ...
- mysql类型与java类型对应异常场景
MySQL的bigint unsigned类型,对应java的BigInteger类型,在基于mybatis框架时,如果我将bigint unsigned类型的字段的返回放在一个map的返回类型中时. ...
- Hibernate关联映射之_一对多
domain: package org.zln.hibernate.domain; import java.util.Set; /** * 部门Domain对象 * Created by sherry ...
- dva的基本用法
dva是一个状态管理工具,整合了redux,redux-saga,react-router,fetch等框架,目前只能用于react的状态管理 1. dva的models dva的主要作用还是整合了r ...
- EditPlus直接连接Linux服务器编辑文本文件
填写好:描述,ip地址,用户名,密码, 然后点下面的高级选项: 然后返回上一个页面,继续 确定 OK: 然后,在主界面左侧点倒三角: 就可以选择我们之前配置的远程服务器地址,弹出提示框 点确定, 就连 ...
- 如何设置项目encoding为utf-8
1.鼠标右键点击项目,选择[properties] 2.选择[Resource],在Text file encoding里面选择UTF-8,点击[ok] 大功告成! 木头大哥所发的文章均基于自身实践, ...