看到所有题解都是倒退,却没有一个讲正推的,这里就来讲一下
设
f
i
f_i
fi 表示已经掷到过
i
i
i 个不同面的时候需要的期望次数
初始化
f
0
=
0
f_0=0
f0=0
那么,转移方程显然是
f
i
=
n
−
i
+
1
n
⋅
f
i
−
1
+
n
−
i
n
⋅
f
i
+
1
f_i = \frac{n-i+1}{n} \cdot f_{i-1}+\frac{n-i}{n} \cdot f_i +1
fi=nn−i+1⋅fi−1+nn−i⋅fi+1
化简后得到
f
i
=
f
i
−
1
×
(
n
−
i
+
1
)
+
n
n
−
i
f_i=\frac{f_{i-1}\times(n-i+1)+n}{n-i}
fi=n−ifi−1×(n−i+1)+n
可以发现,如果这样递推到
n
n
n 时,分母就为
0
0
0 了,所以此方法不可行
那么,我们尝试用倒推
设
f
i
f_i
fi 表示已经掷到过
i
i
i 个不同的面后,期望还需要掷多少次才能到
n
n
n 个面。初始化
f
n
=
0
f_n=0
fn=0
转移方程
f
i
=
n
−
i
n
⋅
f
i
+
1
+
i
n
⋅
f
i
+
1
f_i=\frac{n-i}{n} \cdot f_{i+1}+\frac{i}{n} \cdot f_i+1
fi=nn−i⋅fi+1+ni⋅fi+1
化简后得
f
i
=
f
−
i
+
1
+
n
n
−
i
f_i=f-{i+1}+\frac{n}{n-i}
fi=f−i+1+n−in
这样,就不会出现分母为
0
0
0 的情况了,答案为
f
0
f_0
f0
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int Maxn=1010;
double f[Maxn];
int n,T;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
f[n]=0.0;
for(int i=n-1;i>=0;--i)
f[i]=f[i+1]+(n*1.0)/((n-i)*1.0);
printf("%.2lf\n",f[0]);
}
return 0;
}