洛谷 SP1026 FAVDICE - Favorite Dice
题目描述
BuggyD loves to carry his favorite die around. Perhaps you wonder why it's his favorite? Well, his die is magical and can be transformed into an N-sided unbiased die with the push of a button. Now BuggyD wants to learn more about his die, so he raises a question:
What is the expected number of throws of his die while it has N sides so that each number is rolled at least once?
输入格式
The first line of the input contains an integer t, the number of test cases. t test cases follow.
Each test case consists of a single line containing a single integer N (1 <= N <= 1000) - the number of sides on BuggyD's die.
输出格式
For each test case, print one line containing the expected number of times BuggyD needs to throw his N-sided die so that each number appears at least once. The expected number must be accurate to 2 decimal digits.
题意翻译
一个n面的骰子,求期望掷几次能使得每一面都被掷到。
题解:
以前拐入了一个求期望的误区,就是数学方法直接按定义来求期望。但是很快思路就卡死了,因为数学方法求期望实在不适合数据范围比较大的计算机题。
(还是蒟蒻太菜了啊)
那么应该使用什么方法呢?
DP。
期望DP。
对于期望DP的一般思路,蒟蒻在这篇博客中有着讲解:
那么这道题就是采用的基本期望DP的方程设计思路和动规转移思路:设置dp[i]表示已经掷过i面,还期望掷几次能掷完n面。这也是期望DP的一个基础的转移方程设计思路,就是表示由i状态变成最终状态的期望。
转移的时候考虑两种情况的贡献和:第一种情况是再掷的时候掷到已经掷过的面。第二种情况是再掷的时候掷到新面。那么转移方程也就是:
化简:
然后转移的时候使用刷表法,也就是逆向枚举。因为初值是dp[n]=0,答案是dp[0]。
关于填表和刷表,蒟蒻的理解:
代码:
#include<cstdio>
#include<cstring>
using namespace std;
int t;
int n;
double dp[1010];
int main()
{
scanf("%d",&t);
while(t--)
{
memset(dp,0,sizeof(dp));
scanf("%d",&n);
for(int i=n-1;i>=0;i--)
dp[i]=dp[i+1]+(double)n/(n-i);
printf("%.2lf
",dp[0]);
}
return 0;
}