bzoj1426 收集邮票(递推+概率期望)

来源:互联网 发布:外贸邦海关数据 编辑:程序博客网 时间:2024/06/06 04:08

分析:
和这道题蛮像的,主要分析转自这里

受到UVa10288启发之后,我们就可以很容易的求出g[i]表示当前有i张邮票,得到n张得期望步数
这里写图片描述
同时我们定义pr(x,i)表示买x次能从i种买到n种的概率
实际pr就是这个:

假设我们现在手里已经有了k图案,令s=k/n,拿一个新的图案需要t次的概率:s^(t-1)*(1-s)

则有
这里写图片描述

设计状态:f[i][j]表示现在有i张不同的邮票,下一次购买需要j+1元,得到n张邮票的期望花费

  • i/n的概率,转移到f[i][j+1],花费是j
  • (n-i)/n的概率,转移到f[i+1][j+1],花费是j

所以状态转移方程显而易见:
f[i][j]=j + f[i][j+1] * i/n + f[i+1][j+1] * (n-i)/n

但是f[i][j]的j是无限的,所以这个递推无法进行,考虑f[i][j]与f[i][j+1]的关系,有


且有


那么有f[i][j]关于f[i+1][j]的状态转移:


再来看看我们的求解,我们只关心f[0][1]是多少,所以,对于j不等于1的情况我们可以忽略

那么定义F[i]表示f[i][1],有


特别的,f[n][1]=0,所以F[n]=0

我们已知F[n]的值与g[0]~g[n]的值,那么我们就可以递推出f[0][1]=F[0]的值,问题到此就可以解决了

//这里写代码片#include<cstdio>#include<cstring>#include<iostream>using namespace std;double g[10010],f[10010];int n;int main(){    scanf("%d",&n);    g[n]=0.0;    for (int i=n-1;i>=0;i--)        g[i]=g[i+1]+(double)n/(n-i);    for (int i=n-1;i>=0;i--)        f[i]=(((f[i+1]+g[i+1])*(double)(n-i)/n)+g[i]*(double)i/n+1.0)*(double)n,f[i]/=(double)n-i;    printf("%.2lf",f[0]);    return 0;}
原创粉丝点击