正推不行就逆推!

  经典问题:生日悖论

  换成其互斥事件: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 带你飞 概率期望的更多相关文章

  1. KUANGBIN带你飞

    KUANGBIN带你飞 全专题整理 https://www.cnblogs.com/slzk/articles/7402292.html 专题一 简单搜索 POJ 1321 棋盘问题    //201 ...

  2. [kuangbin带你飞]专题1-23题目清单总结

    [kuangbin带你飞]专题1-23 专题一 简单搜索 POJ 1321 棋盘问题POJ 2251 Dungeon MasterPOJ 3278 Catch That CowPOJ 3279 Fli ...

  3. 「kuangbin带你飞」专题二十 斜率DP

    layout: post title: 「kuangbin带你飞」专题二十 斜率DP author: "luowentaoaa" catalog: true tags: mathj ...

  4. 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开

    [kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...

  5. Tarjan 联通图 Kuangbin 带你飞 联通图题目及部分联通图题目

    Tarjan算法就不说了 想学看这 https://www.byvoid.com/blog/scc-tarjan/ https://www.byvoid.com/blog/biconnect/ 下面是 ...

  6. 「kuangbin带你飞」专题十四 数论基础

    layout: post title: 「kuangbin带你飞」专题十四 数论基础 author: "luowentaoaa" catalog: true tags: mathj ...

  7. 「kuangbin带你飞」专题二十二 区间DP

    layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...

  8. 「kuangbin带你飞」专题十九 矩阵

    layout: post title: 「kuangbin带你飞」专题十九 矩阵 author: "luowentaoaa" catalog: true tags: mathjax ...

  9. 「kuangbin带你飞」专题十八 后缀数组

    layout: post title: 「kuangbin带你飞」专题十八 后缀数组 author: "luowentaoaa" catalog: true tags: - kua ...

随机推荐

  1. [Binary Search] Leetcode 35, 74

    35. Search Insert Position Description Given a sorted array and a target value, return the index if ...

  2. Windows server 2012 R2开机进入cmd,关闭后黑屏问题

    原因分析: 因为自己在卸载IIS的时候,不小心卸载了.net framework,系统没有了图形界面(由完整模式Full变为了核心模式core),需要重新恢复.net framework4.5. 解决 ...

  3. lnmp1.4,400,500,错误

    Thinkphp5或其他主流框架,入口文件未放在根目录下,比如Thinkphp5 入口文件放在/public/index.php vhost需要指向/public目录 一键安装包通常会报 open_b ...

  4. WebKit资源加载和网络栈

    webkit笔记,主要来自 朱永盛 <WebKit技术内幕> 学习笔记,转载就注明原著,该书是国内仅有的Webkit内核的书籍,学习的好导师,推荐有兴趣的朋友可以购买 WebKit资源加载 ...

  5. 浅拷贝&深拷贝&Copy On Write(Sring类)

    String类的三种实现 浅拷贝 class String { public: String(const char* pdata)//构造函数 :_pdata(]) { strcpy(_pdata, ...

  6. AngularJS设置文本样式小程序

    做了一个这样的程序通过选择框选择样式,下面的段落样式跟着改变.就是想做这么一个东西. <!DOCTYPE html> <html lang="en"> &l ...

  7. JSON使用(4)

    把JSON文本转换为JavaScript对象 JSON最常见的用法之一,是从web服务器上读取JSON数据(作为文件或作为HttpRequest),将JSON数据转换为JavaScript对象,然后在 ...

  8. hdu 1286 找新朋友 (欧拉函数)

    找新朋友 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  9. hdu4035 Maze 【期望dp + 数学】

    题目链接 BZOJ4035 题解 神题啊...orz 不过网上题解好难看,数学推导不写\(Latex\)怎么看..[Latex中毒晚期] 我们由题当然能很快写出\(dp\)方程 设\(f[i]\)表示 ...

  10. BZOJ day2_plus

    大半夜的刷b站,好爽啊... 突破十九题 1008105110591088117911911192143218761951196821402242243824562463276128184720