0
点赞
收藏
分享

微信扫一扫

BZOJ 1426 收集邮票 期望dp


Description


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


Input


一行,一个数字N N<=10000


Output


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


Sample Input


3


Sample Output


21.25


HINT
























​​传送门​​


看的题解orz……


好复杂啊= =跟着它推了半天。。。


对了题目中“第k张邮票k元钱”,意思是你买的第k张而不是顺序里的第k张。。。


就当是给他的一个补充说明了。。


(无耻拿几个图)




设g(i)表示当前手上有i种邮票,要买到n种邮票还要买的期望张数。


pr(x,i)表示当前手上有i种邮票,又买了x张,买到n种邮票的概率。


g(i)如何表示?假设买一张就可以买到(i+1)种,买2张就可以买到(i+1)种……相当于枚举x


于是直接表示出g(i)的表达式(pr(x,i)直接表示出)


BZOJ 1426  收集邮票   期望dp_c++


(无耻贴图=v=)


这个式子看似是无穷的,但是假如从g(i+1)推来弄一个递推的表达式,


那么就可以化无穷为有限的递推。


用错位相减法可以搞出来g(i)=g(i+1)+n/(n-i)


然后用f(i,j)表示有i种邮票,在买第j张(或者下一张要n)要买到n种的期望花费,


同理是可以枚举j的,然后统计期望花费,然而j是无穷的,


根据f(i,j)的定义式又可以写出这么个东西:


BZOJ 1426  收集邮票   期望dp_c++_02


(唔。。偷偷拿个图)


这个式子是什么意义呢,,x枚举的是剩余买的次数,


那么还要买x次,从下次开始,先是j元,再是(j+1)元……


然后f(i,j)还可以写出一个递推的式子,因为可以考虑只买下一张邮票,


假如说买了下一张变成了(i+1)种,概率是i/n,(i+1)种的期望是f(i+1,j+1)


假如说买了下一张还是i种,概率是(n-i)/n,i种的期望是f(i,j+1)


也就是:


BZOJ 1426  收集邮票   期望dp_c++_03


有了定义式和递推式,然而递推式子里有一个无穷的j,


所以再用f(i,j+1)-f(i,j),得出


BZOJ 1426  收集邮票   期望dp_#include_04


竟然刚好是g(i)……太神了。。


于是可以把f(i,j)递推式里面的f(i,j+1),f(i+1,j+1)代掉了,然后化简,


但是化简之后还剩下f(i,j)?能够发现,j在递推中没有变,都是j项,


所以j项是可以直接省去的,答案是f(0,1),那么j都是1即可。


就得到了:


BZOJ 1426  收集邮票   期望dp_c++_05


……慌张。。就这么推完了。。




再次orz……


















#include<bits/stdc++.h>
using namespace std;
int n;
double g[10005],f[10005];
int main(){
scanf("%d",&n);
for (int i=n-1;~i;i--) g[i]=g[i+1]+(double)n/(double)(n-i);
for (int i=n-1;~i;i--) f[i]=(g[i]*i+(g[i+1]+f[i+1])*(n-i)+n)/(double)(n-i);
printf("%.2lf\n",f[0]);
return 0;
}



举报

相关推荐

0 条评论