LightOJ1234調和級數求和公式
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 |
網上的題解主要有兩個思路, 思路1: 由於 n 最大是 1e8的大小,顯然打不了這麼大的表.於是考慮每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;
}