SP1026 FAVDICE - Favorite Dice 题解

题目链接

看到所有题解都是倒退,却没有一个讲正推的,这里就来讲一下

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=nni+1fi1+nnifi+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=nifi1×(ni+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=nnifi+1+nifi+1
化简后得 f i = f − i + 1 + n n − i f_i=f-{i+1}+\frac{n}{n-i} fi=fi+1+nin
这样,就不会出现分母为 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;
}

猜你喜欢

转载自blog.csdn.net/Brian_Pan_/article/details/110133393