题目
有 n 种不同的邮票,皮皮想收集所有种类的邮票。唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是 n 种邮票中的哪一种是等概率的,概率均为 1/n。但是由于凡凡也很喜欢邮票,所以皮皮购买第 k 次邮票需要支付 k 元钱。
现在皮皮手中没有邮票,皮皮想知道自己得到所有种类的邮票需要花费的钱数目的期望。
输入格式
一行,一个数字 N(N≤10000)。
输出格式
输出要付出多少钱,保留二位小数。
思路
折磨了我很久的一道题,期望题初学是真的仙。。。
tag:dalao给的期望定义状态公式:“已经……还需要……的期望”
言归正传!
首先我们知道当买X次邮票收集成功时需要花费的钱数目为1+2+、、、+ X X X= X 2 + X 2 \frac{X^2+X}{2} 2X2+X
那么我们解题方向就成功的转化成了收集所有种类邮票的次数。
根据钱数目公式我们需要用两个数组分别表示 X 2 X^2 X2和 X X X
那么!用 a [ i ] a[i] a[i]表示收集i个邮票后还需要的次数期望;
f [ i ] f[i] f[i]表示收集i个邮票后还需要的次数平方的期望。(注意不是期望的平方,不然 a [ i ] 2 a[i]^2 a[i]2就行了还要什么自行车)
因为代表的是还需要的次数所以很显然收集到n个邮票后的期望为0,即a[n]=0,f[n]=0;
更简单的,输出的 X 2 + X 2 \frac{X^2+X}{2} 2X2+X就为 f [ 0 ] + a [ 0 ] 2 \frac{f[0]+a[0]}{2} 2f[0]+a[0]
现在我们来考虑a[i]
每次买邮票存在两种情况:
1、买到买到过的邮票种类概率求法,即(a[i]+1)* i n \frac{i}{n} ni ;(a[i]本身表示收集i个邮票后还需要的次数,那么这个次数+1应该不需要多解释了吧!?)
2、买到没买到过的邮票种类概率求法,即(a[i+1]+1)* n − i n \frac{n-i}{n} nn−i .
那么a[i]的转移方程就为
a[i]=(a[i]+1)* i n \frac{i}{n} ni + (a[i+1]+1)* n − i n \frac{n-i}{n} nn−i .
给他化简一下:a[i]=a[i+1]+ n − i n \frac{n-i}{n} nn−i .(为什么不化简成a[i]表示成a[i+1]的形式?我们只知道a[n]的值,所以采取倒推的方式)
这里可能有的小伙伴存在一个误区:我不化简为什么答案是错的?不化简计算时a[i]的值为0,不满足我们赋予他的含义(收集i个邮票后还需要的次数期望)。数学很重要的一点在于我们可以根据一些我们赋予他的字符属性写出符合逻辑的公式,那么通过已知条件对公式本身进行一些转化和化简是一种很实用的手段。
再来考虑f[i]
次数平分怎么求呢,次数+1再解开平分即可,解开即为(f[i]+2*a[i]+1);
PS:不会有人想的是 a [ i ] 2 a[i]^2 a[i]2而不是f[i]吧?不会吧不会吧(手动疯狂狗头)还是上面的那句话,得到的是次数平方的期望而不是次数期望的平方。
f[i]的转移方程就为
f[i]=(f[i]+2 * a[i]+1) * i n \frac{i}{n} ni + (f[i+1]+2*a[i+1]+1) * n − i n \frac{n-i}{n} nn−i;
化简一下:f[i]= 2 i n − i \frac{2i}{n-i} n−i2i* a[i]+2*a[i+1]+f[i+1]+ n n − i \frac{n}{n-i} n−in.
接下来就是代码了
注意精度
#include<bits/stdc++.h>
using namespace std;
#define ll long long
double a[10007];
double f[10007];
int main()
{
double n;
cin>>n;
for(int i=n-1;i>=0;i--)
{
a[i]=a[i+1]+n/(n-i*1.0);
f[i]=2.0*i/(n-i*1.0)*a[i]+2.0*a[i+1]+f[i+1]+n/(n-i*1.0);
}
printf("%.2lf\n",(f[0]+a[0])/2.0);
return 0;
}
总结
概率和期望真√8仙,写其他算法就只随便动几下笔,这玩意儿能用好多页草稿!还废脑子o…orz