调和级数表示如下的一个数学式子
∑
i
=
1
n
1
/
i
\sum\nolimits_{i=1}^{n} 1/i
∑i=1n1/i
这个数学公式现在还没有一个确切的公式,但当n很大时,欧拉给出了一个近似的求解公式。
f(n)≈ln(n)+C+1/2*n
欧拉常数值:C≈0.57721566490153286060651209
但当n比较小时,这个式子就不好用啦。
现在看两道和这个看起来有点关系的题目。
1、LightOJ 1234
题目链接:https://vjudge.net/problem/LightOJ-1234
题意:给出一个n,求调和级数的值。
思路:小于1e6时直接打表,大于1e6时带入公式
代码:
#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
const double C=0.57721566490153286060651209;
double ans[1000010];
void init()
{
ans[0]=0;
for(int i=1;i<=1000000;i++)
{
ans[i]=ans[i-1]+1.0/i;
}
}
int main()
{
init();
int T;
scanf("%d",&T);
int cas=1;
while(T--)
{
int n;
scanf("%d",&n);
if(n<=1000000) printf("Case %d: %.10lf\n",cas++,ans[n]);
else printf("Case %d: %.10lf\n",cas++,log(n*1.0)+C+1.0/(2.0*n));
}
return 0;
}
2、LightOJ 1245
题目链接:https://vjudge.net/problem/LightOJ-1245
题意: n * ∑ i = 1 n 1 / i = ? \sum_{i=1}^{n} 1/i = ? ∑i=1n1/i=? n / i 像下取整
思路:这一题就不能用调和级数的公式来做啦。所以,这一题,是,打表找规律。emmmmmm
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long
int main()
{
int T;
scanf("%d",&T);
int cas=1;
while(T--)
{
int n;
scanf("%d",&n);
LL ans=0;
int temp=sqrt(n);
for(int i=1;i<=temp;i++)
{
ans+=n*1LL/i;
}
ans*=2LL;
ans-=temp*temp*1LL;
printf("Case %d: %lld\n",cas++,ans);
}
return 0;
}