当前位置: 代码迷 >> 综合 >> LightOJ - 1234 Harmonic Number(调和级数,分块打表)
  详细解决方案

LightOJ - 1234 Harmonic Number(调和级数,分块打表)

热度:59   发布时间:2023-12-09 20:16:02.0

链接:LightOJ - 1234 Harmonic Number

题意:

给出 T ( ≤ 10000 ) T(\le 10000) T(10000) n ( 1 ≤ n ≤ 1 0 8 ) n(1\le n\le10^8) n(1n108),求调和级数 H ( n ) = ∑ k = 1 n 1 k                H(n)=\displaystyle\sum_{k=1}^{n}\frac{1}{k}\;\;\;\;\;\;\; H(n)=k=1n?k1?(精确到 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;
}
  相关解决方案