Favorite Dice SPOJ - FAVDICE && 概率dp

题目大意

一个N面骰子,问把每一面都至少掷出一次期望次数是多少?

input

2
1
12

output

1.00
37.24

idea

一开始的时候,一直在想扔出一面的期望是1,扔出两面的期望是(1 - 1/n) * 2, 扔出三面的期望是(1 - 2 / n) * 3 ….试了试样例,发现不对。
正确的应该是4/4 + 4/3 + 4/2 + 4/1,假设n是4的话。
首先扔第一面的时候,是1这个没有问题。
扔第二面的时候,期望是3/4,因为对于第二次扔,可能1次扔中,2次扔中,3次扔中…无穷多次扔中。
这个时候的期望就是(1 + 1/4 + 1/4 * 1/4 + 1/4 * 1/4 * 1/4 + …) 其实这里的每一项都是1/4 * 1 * 1/4 * 1 * 1/4 * 1的,好好理解一下,然后这个就是等比级数。
等比级数的求和公式:
当| r | < 1 时,limx→∞ Sn = a1 / (1 - r) 此时等比级数收敛。
所以最终结果就是∑(n / i)

上面是理性推出来的做法
看了另一种做法就是概率dp,发现这个东西真的好厉害的
我觉得对于这种可以做无穷多次的,就是要想到这种dp的思想
dp[i]表示已经有了i种需要有的状态,推到最终状态需要的期望次数。
很显然dp[n] = 0。
然后开始逆推。对于当前的状态,如果在做一次操作,要么保持原有的状态dp[i],这种概率是i/n,要么出现新的一种状态,这种概率是(n - i) / n.
dp[i] = i / n * (dp[i] + 1) + (n - i) / n * (dp[i + 1] + 1);
化简下就ok,dp[0]就是答案。

code

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e4 + 100;
double dp[maxn];

int main()
{
    int t;
    scanf("%d", &t);
    while(t--) {
        int n;
        scanf("%d", &n);
        dp[n] = 0;
        for(int i = n - 1; i >= 0; i--) {
            dp[i] = dp[i + 1] + (double)n / (n - i);
        }
        printf("%.2lf\n", dp[0]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值