1. 程式人生 > >LightOJ1234調和級數求和公式

LightOJ1234調和級數求和公式

1234 - Harmonic Number
Time Limit: 3 second(s) Memory Limit: 32 MB

In mathematics, the nth harmonic number is the sum of the reciprocals of the first n natural numbers:

In this problem, you are given n, you have to find Hn.

Input

Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case starts with a line containing an integer n (1 ≤ n ≤ 108).

Output

For each case, print the case number and the nth harmonic number. Errors less than 10-8 will be ignored.

Sample Input

Output for Sample Input

12

1

2

3

4

5

6

7

8

9

90000000

99999999

100000000

Case 1: 1

Case 2: 1.5

Case 3: 1.8333333333

Case 4: 2.0833333333

Case 5: 2.2833333333

Case 6: 2.450

Case 7: 2.5928571429

Case 8: 2.7178571429

Case 9: 2.8289682540

Case 10: 18.8925358988

Case 11: 18.9978964039

Case 12: 18.9978964139

PROBLEM SETTER: JANE ALAM JAN 題意: 求n級調和級數之和:h[n] = 1/1 + 1/2 + 1/3 + 1/4 +…+ 1/n。(n <= 1e8)。要求誤差不超過1e-8. 
網上的題解主要有兩個思路, 思路1:  由於 n 最大是 1e8的大小,顯然打不了這麼大的表.於是考慮每100個數記錄一下.
於是對於在最後一個區域中時,然後詢問時就是在這個基礎上最多在查100個數.
程式碼
/**
    調和級數和打表,但是因為n是1e8次方,所以想到分割槽域打表.
    每100個打一個表,
    於是對於在最後一個區域中時,然後詢問時就是在這個基礎上最多在查100個數.
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
double arr[maxn];
void init() {
    arr[0] = 0;
    double temp = 0;
    for(int i=1;i<maxn*100;i++) {
        temp = temp + 1.0/i;
        if(i % 100 == 0) arr[i/100] = temp;
    }
}
int main()
{
    init();
    int caset,cas = 0;scanf("%d",&caset);
    while(caset--) {
        int n;scanf("%d",&n);
        int pos = n / 100,now = n % 100;
        double ans = arr[pos];
        for(int i=1+pos*100;i<=n;i++) {
            ans = ans + 1.0 / i;
        }
        printf("Case %d: %.10lf\n",++cas,ans);
    }
    return 0;
}

思路2 利用公式

當n > 1e6時可以用公式:

調和級數求和的式子 趨近值為 :
   h[n]=(log(n * 1.0) + log(n + 1.0)/2.0 + 1.0/(6.0 * n * (n + 1)) - 1.0 / (30.0 * n * n * (n + 1) * (n + 1)) + r。
   其中r為尤拉常數:
   r=0.57721566490153286060651209008240243104215933593992.

我記得 一般為 h[n] = In(n+1) + r ,但是這裡的精度不夠.上面的好像更精確點,

程式碼

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
const double r = 0.57721566490153286060651209008240243104215933593992;
double arr[maxn];
void init() {
    arr[0] = 0;
    double temp = 0;
    for(int i=1;i<maxn;i++) {
        temp = temp + 1.0/i;
        arr[i] = temp;
    }
}
double func(int x) {
    double res = (log(x * 1.0) + log(x + 1.0)) / 2;
    res += 1.0 / (6.0 * x * (x + 1));
    res -= 1.0 / (30.0 * x * x * ( x + 1) * (x + 1));
    return res + r;
}
int main()
{
    init();
    int caset,cas = 0;scanf("%d",&caset);
    while(caset--) {
        int n;scanf("%d",&n);
        double ans;
        if( n < maxn-5 ) ans = arr[n];
        else ans = func(n);
        printf("Case %d: %.10lf\n",++cas,ans);
    }
    return 0;
}