正推不行就逆推!

  经典问题:生日悖论

  换成其互斥事件: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. Linux-获得命令帮助man

    date:显示当前系统时间,修改时间 clock,hwclock:显示硬件时间 cal:calendar,查看日历 计时器靠晶体振荡器来完成计时 Linux: 实时时钟,rtc,real time c ...

  2. 第二十篇 sys模块

    修改环境变量 import sys sys.path.append() 但是,这种修复方式只是临时修改 如果要永久修改,就要电脑里配置环境变量. sys.argv:命令行参数List,第一个元素是程序 ...

  3. 常用模块(chardet)

    作用:检测二进制的编码格式,不是百分百正确 import chardet f = open('test.txt', 'rb')data = f.read()print(data)result = ch ...

  4. python第三天(dictionary应用)转

    1.题目: python实现英文文章中出现单词频率的统计   前言: 这道题在实际应用场景中使用比较广泛,比如统计历年来四六级考试中出现的高频词汇,记得李笑来就利用他的编程技能出版过一本背单词的畅销书 ...

  5. HDU 4436 str2int(后缀自动机)(2012 Asia Tianjin Regional Contest)

    Problem Description In this problem, you are given several strings that contain only digits from '0' ...

  6. UVA 11297 Census(二维线段树)

    Description This year, there have been many problems with population calculations, since in some cit ...

  7. POJ 1463 Strategic game(二分图最大匹配)

    Description Bob enjoys playing computer games, especially strategic games, but sometimes he cannot f ...

  8. lintcode-117-跳跃游戏 II

    117-跳跃游戏 II 给出一个非负整数数组,你最初定位在数组的第一个位置. 数组中的每个元素代表你在那个位置可以跳跃的最大长度. 你的目标是使用最少的跳跃次数到达数组的最后一个位置. 样例 给出数组 ...

  9. 微信PC端授权页面提示授权入口所在域名为空

    做第三方微信平台的时候做授权页面,用window.open方法从第三方平台页面打开新的授权标签页. 在IE浏览器上出问题,提示如下: 在chrome和firefox浏览器上正常. 搜了一下,发现微信是 ...

  10. media="screen"是什么意思?

    <link rel="stylesheet" href="css/main.css" type="text/css" media=&q ...