题目描述
HKE最近编写了一个函数 ( ext{rand}(l,r)),其中 (l,r) 为正整数且 (l le r)。这个函数会等概率返回区间 ([l,r]) 中任意一个正整数。然后,他又编写了一个函数:
int work(int x){
if(x==1) return 0;
else return work(rand(1,x))+1;
}
现在给定一个正整数 (n),请问 ( ext{work}(n)) 的返回值的期望值是多少?对于(70\%)的数据,(nle 10^6),对于(100\%)的数据,(n<2^{31})。
分析
设(f_i)为( ext{work}(i))的期望,那么
[f_i=dfrac1{i}sum_{j=1}^i f_j+1
]
边界(f_1=0)。记(S_i)为(f_i)的前(i)项和,则
[f_i=dfrac1iS_i+1
]
同理有(f_{i-1}=dfrac1iS_{i-1}+1)。将两式相减得
[if_i-(i-1)f_{i-1}=S_i-S_{i-1}+1
]
整理即得
[f_i=f_{i-1}+dfrac1{i-1}
]
从而
[f_i=sum_{j=1}^{i-1}+1=H_{i-1}+1
]
其中(H_{i-1})为第(i-1)项调和数。
对于(70\%)的数据,可以(O(n))递推(f_n)。注意到当(n)充分大时,有(H_napprox ln n+gamma),其中(gammaapprox 0.57721566490153286)为欧拉常数,(O(1))即可计算。
Code
#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
const double g=0.57721566490153286;
double sum;
int n;
int main()
{
scanf("%d",&n);
if(n<=1e6)
for(int i=1;i<=n-1;++i)
sum+=1.0/i;
else
sum=log(n)+g;
printf("%.5lf
",n==1?0:sum+1.0);
}