[BZOJ]1426 收集邮票 概率与期望

1426: 收集邮票

Time Limit: 1 Sec   Memory Limit: 162 MB
Submit: 500   Solved: 413
[ Submit][ Status][ Discuss]

Description

有n种不同的邮票,皮皮想收集所有种类的邮票。唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是n种邮票中的哪一种是等概率的,概率均为1/n。但是由于凡凡也很喜欢邮票,所以皮皮购买第k张邮票需要支付k元钱。现在皮皮手中没有邮票,皮皮想知道自己得到所有种类的邮票需要花费的钱数目的期望。

Input

一行,一个数字NN<=10000

Output

要付出多少钱.保留二位小数

Sample Input

3

Sample Output

21.25

HINT

Source

[ Submit][ Status][ Discuss]


HOMEBack

---------------------------------


这道题一开始有一个非常naive的写法...那是因为我忽略了买一张邮票还要花钱...我还以为求张数心里暗想傻逼入门题... 还是我太naive了...

首先这道题比较难以处理的就是钱. 那么我们所需要知道的实际上当前是买的是第几张(第几张就是多少钱). 那么如果我们要用f[i]表示当前已经收集了i种还需花多少钱才能收集完的话肯定是不够的, 因为转移的时候需要知道当前是买的第几张. 所以另外维护一个数组g[i]表示当已经有i种还需买多少次才能收集完.

首先很明显f[0]就是答案. 假设已经求出g数组, 考虑f数组的转移.

首先对于f[i], 有i/n的几率转移到f[i], 就是说买中了已经收集到的邮票. 那么考虑转移到f[i的代价. ]因为我们知道我们期望还需买g[i]次, 那么当前就是第g[i] + 1次. 那么这次的花费就是g[i] + 1.

那么 转移到f[i]就是  (i /n) *  ( f[i] + g[i] + 1).

对于(n - i) / n的几率转移到f[i + 1], 那么同上分析花费就是: ((n - i) / n) * (f[i +1] + g[i + 1] + 1). 综上:

f[i] = (i /n) *  ( f[i] + g[i] + 1) +( (n - i) / n) *  (f[i +1] + g[i + 1] + 1).

化简之后就是:

f[i] = f[i + 1] + g[i + 1] +( i / (n - i)) * g[i] + n / (n - i) + 1.

对于g数组 g[i] = i / n * g[i] + (n -  i) / n * g[i + 1] .

化简得: g[i] = g[i + 1] + n / (n - i);

还有一种用公式推导的办法, 也很有价值看看 :http://www.cnblogs.com/DaD3zZ-Beyonder/p/5904217.html.(超链接出了点问题).

#include<stdio.h>
const int maxn = 10010;
double f[maxn], g[maxn], n;
int main(){
	scanf("%lf", &n);
	for(int i = n - 1; ~i; --i)
		g[i] = g[i + 1] + n / (n - i);
	for(int i = n - 1; ~i; --i)
		f[i] = f[i + 1] + g[i + 1] + i / (n - i) * g[i] + n / (n - i);
	printf("%0.2lf\n", f[0]);
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值