题意
有n种彩票,每次抽取一张新彩票,每种彩票出现的概率始终相同。求集齐所有种类彩票的期望抽奖次数,并用带分数表示。
题解
假设当前已经集齐了k种彩票,接下来抽到新一种彩票的概率是\frac{n-k}{n},则抽到新一种的期望次数是\frac{n}{n-k},则总期望次数是:
E=\sum_{k=0}^{n-1} \frac{n}{n-k}=n\sum_{k=0}^{n-1} \frac{1}{n-k}
值得注意的是期望与概率的倒数关系并不是那么的显然,有时间需要写一篇文章来讨论这件事情。
代码
写的稍微丑了一点,这个带分数处理的类是现场手写的,比较粗糙。(竞赛码风和工程区别还是很大的啊)
#include <bits/stdc++.h>
using namespace std;
long long gcd(long long a, long long b)
{
return (b == 0 ? a : gcd(b, a % b));
}
long long read()
{
long long x;
cin >> x;
return x;
}
struct frac
{
long long intpart;
long long above;
long long below;
void yuefen()
{
long long x = gcd(above, below);
above /= x;
below /= x;
}
void quzheng()
{
yuefen();
if (above >= below)
{
intpart += (long long)(above / below);
above -= (below * (long long)(above / below));
}
}
frac operator+(const frac &obj) const
{
frac tmp;
tmp.intpart = intpart + obj.intpart;
tmp.above = above * obj.below + below * obj.above;
tmp.below = below * obj.below;
return tmp;
}
} ans, cur;
long long cntdigit(long long x)
{
int ans = 0;
while (x)
{
x /= 10;
++ans;
}
return ans;
}
long long n;
signed main()
{
while (scanf("%lld", &n) != EOF)
{
for (long long i = 0; i <= n - 1; ++i)
{
cur.intpart = 0;
cur.above = n;
cur.below = n - i;
cur.quzheng();
if (i == 0)
ans = cur;
else
ans = ans + cur, ans.quzheng();
}
if (ans.above == 0)
{
cout << ans.intpart << endl;
}
else if (cntdigit(ans.intpart) == 0)
{
printf("%lld\n", ans.above);
for (int i = 1; i <= cntdigit(max(ans.above, ans.below)); ++i)
printf("-");
printf("\n");
printf("%lld\n", ans.below);
}
else
{
for (int i = 1; i <= cntdigit(ans.intpart) + 1; ++i)
printf(" ");
printf("%lld", ans.above);
printf("\n%lld ", ans.intpart);
for (int i = 1; i <= cntdigit(max(ans.above, ans.below)); ++i)
printf("-");
printf("\n");
for (int i = 1; i <= cntdigit(ans.intpart) + 1; ++i)
printf(" ");
printf("%lld\n", ans.below);
}
}
}