按步长预处理
#include<cstdio>
using namespace std;
/*
计算H(n)=1/1+1/2+1/3+……1/n (1<=n<=e8)
如果存储所有调和级数的值,存储不下
设定一个步长stept,每100存储一个Hn
*/
const int INF=1e8+5;//最大值
const int maxn=1e6+5;
const int stept=100;//步长
double cnt[maxn];//每个步长存储一个Hn
//预处理出调和级数
void init()
{
cnt[0]=0.0;
double sum=0.0;
for(int i=1;i<=INF;i++)
{
sum+=1.0/i;
if(i%stept==0)//按步长存储
{
cnt[i/stept]=sum;
}
}
}
int main()
{
int T,kase=0;
init();
int n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int m=n/stept;//得到当前是多少步长
double ans=cnt[m];//取表中的和
//[m+1,n]直接计算
for(int i=stept*m+1;i<=n;i++)
{
ans+=1.0/i;
}
printf("Case %d: %.10lf\n",++kase,ans);
}
return 0;
}
预处理+欧拉公式
#include<cstdio>
#include<cmath>
using namespace std;
/*
计算H(n)=1/1+1/2+1/3+……1/n (1<=n<=e8)
如果存储所有调和级数的值,存储不下
H(n)=ln(n)+R+1/(2*n);(R为欧拉常数)
R=0.57721566490153286060651209;
*/
const int maxn=1e4+5;
double cnt[maxn];
const double R=0.57721566490153286060651209;//欧拉常数
//预处理出调和级数
void init()
{
cnt[0]=0.0;
double sum=0.0;
for(int i=1;i<=maxn;i++)
{
sum+=1.0/i;
cnt[i]=sum;
}
}
int main()
{
int T,kase=0;
init();
int n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
double ans=0.0;
if(n<maxn)//n比较小,预处理
{
ans=cnt[n];
}
else
{
ans=log(n)+R+1.0/(2*n);//n比较大,用欧拉公式
}
printf("Case %d: %.10lf\n",++kase,ans);
}
return 0;
}