[BZOJ 2048] [2009国家集训队]书堆 【调和级数】

题目链接:BZOJ - 2048

 

题目分析

只有一本书时,这本书的重心落在桌子边缘上,伸出桌面的长度就是 1/2。

有两本书时,第一本书的重心就落在第二本书的边缘上,两本书的重心落在桌子边缘上,两本书的重心就是在最下面一本书的右端 1/4  处。那么伸出 1/2 + 1/4 。

三本书时,可以再多伸长 3 本书的重心 1/6 。

继续计算可以发现规律,i 本书的重心就落在最下面一本书的右端 1/2i 处。

那么我们要求的伸出的总长度就是 sigma(1 / 2i) = sigma(1 / i) / 2。

sigma(1 / 2i) 就是调和级数求和,如果 n 比较小,我们就直接 O(n) 求,因为 n 比较小的时候用极限公式求误差会比较大。

如果 n 很大,我们就用调和级数的极限公式 sigma(1 / i) (i = 1 to n) = ln(n + 1) + r。r 是欧拉常数,r = 0.5772156649015328...

然后就做完了。

 

代码

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
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
 
using namespace std;
 
typedef double LF;
typedef long long LL;
 
#define r 0.5772156649
 
const LF Eps = 1e-10;
 
LL n, m;
 
LF Ans;
 
int main()
{
    scanf("%lld%lld", &n, &m);
    if (n <= 1000000ll)
    {  
        for (int i = 1; i <= n; ++i)
            Ans += 1.0 / (LF)i;
    }
    else Ans = log((LF)(n + 1)) + r;
    Ans /= 2.0; Ans *= (LF)m;
    printf("%d\n", (int)(Ans - Eps));
    return 0;
}

  

posted @   JoeFan  阅读(398)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示