调和级数
调和级数
调和级数:
\[\sum^{\infty}_{k=1} \frac{1}{k}
\]
该无穷级数发散。
性质:
\[\sum_{k=1}^{n}\frac{1}{k}\approx\log n
\]
证明:
\(\sum_{k=1}^{n}\frac{1}{k}=1+\frac{1}{2}+\frac{1}{3}+···+\frac{1}{n}\)
\(=(1)+(\frac{1}{2}+\frac{1}{3})+(\frac{1}{4}+\frac{1}{5}+\frac{1}{6}+\frac{1}{7})+···+\frac{1}{n}\)
\(\approx 1+1+1+···+1(约\log n 个1)\)
\(=\log n\).
即将 \(n\) 个数拆成 \(O(\log n)\) 个小区间,每个区间的和趋近为 \(1\)。
证毕。
更优秀的估算方法:
\[\sum_{k=1}^{n}\frac{1}{k}\approx \ln n+\gamma+\frac{1}{2n}
\]
其中 \(\gamma\) 为欧拉常数,约等于 \(0.577215664901532 860606512090082402431042159335\)。
当 \(n\to \infty\) 时,\(\frac{1}{2n}\) 趋近于 \(0\)。可忽略。
当 \(n\) 较小时可以暴力 \(O(n)\) 求调和级数值。
较大时就可以用估算法输出 \(\ln n+\gamma\)。
例题 1:洛谷p5147 随机数生成器
设 \(E_i\) 表示函数 \(\operatorname{work}\) 自变量为 \(i\) 时返回值的期望。
那么有:
\[E_n=
\begin{cases}
0 & n=1\\
1+\frac{1}{n}\sum_{k=1}^n E_k &n>1\\
\end{cases}
\]
考虑 \(n>1\) 时的情况。
\[\begin{align}
&\hspace{0.95cm}E_n=1+\frac{1}{n}\sum_{k=1}^n E_k\notag\\
&=>n\times E_n-E_n-n=\sum_{k=1}^{n-1} E_k\\
\end{align}
\]
换元 \(n+1\to n\)。
\[\begin{align}
n\times E_{n+1}-E_n-n-1=\sum_{k=1}^{n-1} E_k\\
\end{align}
\]
联立 \(1\) 式与 \(2\) 式。
\[E_{n+1}-E_{n}=\frac{1}{n}
\]
显然,等式左边是一个差分的形式,而右边是一个分子为 \(1\) 的分数。
写出几项就可以发现,\(E_{n}\) 实际上等于 \(\sum_{i=1}^{n-1} \frac{1}{i}\)。
求调和级数即可。
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define FOR(i,l,r) for(int i=l;i<=r;++i)
#define ROF(i,r,l) for(int i=r;i>=l;--i)
#define mkp make_pair
#define fr first
#define se second
using namespace std;
const double gama=0.5772156649;
int n;double ans=0;
int main() {
cin>>n;
if(n<=10000000) FOR(i,1,n-1) ans+=1.0/i;
else ans=log(n)+gama;
if(n==1) ans=-1;
printf("%.5lf\n",ans+1);
return 0;
}