链接:LightOJ - 1234 Harmonic Number
题意:
给出 T ( ≤ 10000 ) T(\le 10000) T(≤10000)个 n ( 1 ≤ n ≤ 1 0 8 ) n(1\le n\le10^8) n(1≤n≤108),求调和级数 H ( n ) = ∑ k = 1 n 1 k                H(n)=\displaystyle\sum_{k=1}^{n}\frac{1}{k}\;\;\;\;\;\;\; H(n)=k=1∑nk1(精确到 1 0 − 8 10^{-8} 10−8)
分析:
一共要求 T ( ≤ 10000 ) T(\le 10000) T(≤10000)个调和级数,每次都求一遍肯定会超时( O ( T ⋅ n ) O(T\cdot n) O(T⋅n)),考虑打表求一遍把所有答案存起来,但是 n n n有 1 0 8 10^8 108,会爆内存( O ( n ) O(n) O(n))。
但是我们可以折中一下,分块打表,例如以50为一个块,仅存储 H ( 50 ) , H ( 100 ) , H ( 150 ) . . . H(50),H(100),H(150)... H(50),H(100),H(150)...,这样就把空间复杂度降到了 O ( n / 50 ) O(n/50) O(n/50),查询的时候先查表,然后最多只需要再算49个就行了,时间复杂度降到 O ( 50 ∗ T ) O(50*T) O(50∗T)
以下代码:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=1e8+50;
double f[maxn/50];
void init()
{
double sum=0;
f[0]=0;
for(int i=1;i<=maxn;i++)
{
sum+=1.0/i;
if(i%50==0)
f[i/50]=sum;
}
}
int n,m;
double ans=0;
int main()
{
init();
int T,kase=0;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
m=n/50;
ans=f[m];
for(int i=m*50+1;i<=n;i++)
ans+=1.0/i;
printf("Case %d: %.10f\n",++kase,ans);
}
return 0;
}