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

链接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=1nk1(精确到 1 0 − 8 10^{-8} 108



分析:

一共要求 T ( ≤ 10000 ) T(\le 10000) T(10000)个调和级数,每次都求一遍肯定会超时( O ( T ⋅ n ) O(T\cdot n) O(Tn)),考虑打表求一遍把所有答案存起来,但是 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(50T)



以下代码:

#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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值