有n种类型的邮票
问将所有的类型的邮票全部收集起来所要的收集次数期望是多少。
定义 f [ i ] f[i] f[i]为已经收集了 i i i张邮票,还要几次达成目的
f [ i ] = i n f [ i ] + n − i n f [ i + 1 ] + 1 f[i]=\frac{i}{n}f[i]+\frac{n-i}{n}f[i+1]+1 f[i]=nif[i]+nn−if[i+1]+1
化简得到 f [ i ] = f [ i + 1 ] + n n − i f[i]=f[i+1]+\frac{n}{n-i} f[i]=f[i+1]+n−in
所以 f [ 0 ] = n 1 + n 2 + n 3 . . . + n n f[0]=\frac{n}{1}+\frac{n}{2}+\frac{n}{3}...+\frac{n}{n} f[0]=1n+2n+3n...+nn
所以每张邮票期望被拿 1 1 + 1 2 + 1 3 . . . + 1 n \frac{1}{1}+\frac{1}{2}+\frac{1}{3}...+\frac{1}{n} 11+21+31...+n1张
这样就是一个很美妙的性质
比如这题
唯一的区别就是有些邮票拿走后不放回
但是!我们假定他放回,但是只计算第一次抽到的次数
就可以把不放回的邮票也看作放回,但只计算一次费用
就可以使用调和级数公式 O ( 1 ) O(1) O(1)解得
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
double f[maxn];
int main()
{
int t,casenum=0,n;
cin >> t;
for(int i=1;i<=5000;i++)
f[i] = f[i-1] + 1.0/i;
while( t-- )
{
cin >> n;
double ans=0;
for(int i=1;i<=n;i++)
{
int x,type; cin >> x >> type;
if( type==1 ) ans+=x;
else ans+=x*f[n];
}
printf("Case %d: %.5lf\n",++casenum,ans);
}
}