LightOj_1342 Aladdin and the Magical Sticks

时间:2023-03-09 17:19:48
LightOj_1342 Aladdin and the Magical Sticks

题目链接

题意:

  地上有n种棍子, 其中有两种类型, 一种类型是可识别, 一种类型是不可识别, 每个棍子都有一个权值。

  当你捡到可识别的, 那么你以后就不会再捡这个棍子, 如果是不可识别的, 那么你有可能还会捡。

  问将所有棍子收集完的权值的期望。

思路:

  此题借鉴参考了此篇文章:Aladdin and the Magical Sticks

  首先, 这个题初看起来, 和LightOj 1027  A Dangerous Maze有点像, 只不过, 这里是要将所有的门都走遍。

  先引入一个经典的问题:

             邮票收集问题(Coupon Collector Problem)WiKi资料

             几何分布期望的证明过程

  求解邮票收集问题时, 由概率求期望时需要用到几何分布期望, 因此这里给出了几何分布期望的证明过程。 很简洁明了, 还有大量例子结合理解。

  通过上面的问题, 我们可以假设, 我们现在面对的是一个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 <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <string>
#include <vector>
#include <fstream>
#include <iterator>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define eps 1e-6
#define MAXN 5050
#define MAXM 100
#define dd cout<<"debug"<<endl
#define pa {system("pause");}
#define p(x) printf("%d\n", x)
#define pd(x) printf("%.7lf\n", x)
#define k(x) printf("Case %d: ", ++x)
#define s(x) scanf("%d", &x)
#define sd(x) scanf("%lf", &x)
#define mes(x, d) memset(x, d, sizeof(x))
#define do(i, x) for(i = 0; i < x; i ++)
#define dod(i, x, l) for(i = x; i >= l; i --)
#define doe(i, x) for(i = 1; i <= x; i ++)
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 ;
}