题目链接:
http://acm.hust.edu.cn/vjudge/contest/70017#problem/I
题目大意:
求调和级数前n项的和,T个样例,(1≤T≤10000,1≤n≤108)
分析:
直接求肯定TLE,但是如果使用公式的话前几项精度不够,所以前106或107项
O(N)暴力跑出,然后使用高精度的调和级数求和公式,具体可以搜索维基百科或者百度欧拉常数
http://baike.baidu.com/link?url=BWFVuV7oshbt5k7Z2HhvmV84MlXGg2bBE0_MJsQ9ZOJLI8o773s5-Z6k6xK7csGekpFwn0kn539eYbgY-lUDeq
最后的三个公式是表示欧拉常数,y=Hn−2ln n+ln(n+1)−6n(n+1)1+30n2(n+1)21 (Hn为调和级数前n项的和)
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cstring> #include <string> #include <vector> #include <cmath> #include <set> #define MOD 998244353 using namespace std; typedef unsigned long long ull; typedef long long ll;
/*---------------------------head files----------------------------------*/ const double euler = 0.577215664901532860606512090082; double arr[1000009];
void init() { arr[1] = 1.0; for (int i = 2 ; i <= 1000000 ; i ++) { arr[i] = arr[i-1] + 1.0 / i ; } }
int main() { init(); int T,k=1; ll n; scanf("%d",&T); while (T--) { scanf("%lld",&n); printf("Case %d: ",k++); if (n<=1000000) printf("%.8f\n",arr[n]); else { double ans = (log(n) + log(n+1))/2.0; double x1 = 1.0; x1 = x1 / 6.0 / n / (n+1); double x2 = x1 ; x2 = x2 /5.0 / n / (n+1); ans = ans - x1 + x2 ; printf("%.10f\n",ans+euler); } } }
|