【代码超详解】LightOJ 1234 Harmonic Number(技巧,260 ms)

本文介绍了一种在时间和内存限制下计算第N个调和数的算法。通过间隔存储累加结果,避免了全量计算带来的资源消耗。采用2的正整数次方间隔,利用位运算优化计算效率。

一、题目描述

Time limit
3000 ms
Memory limit
32768 kB
OS
Linux
Source
Problem Setter: Jane Alam Jan

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

12
1
2
3
4
5
6
7
8
9
90000000
99999999
100000000

Sample Output

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

二、算法分析说明与代码编写指导

三、AC 代码(260 ms)

n 最大达到 10^8,打表存下结果会超时。而且本题的内存限制是 32 MB,也没有办法存储这么长的结果(一个 double 变量占 8 字节)。
我们可以间隔一定距离来存储累加的结果。例如本代码只存储 H32,H64,H96,……。
在计算 Hn 的时候,将最后一截未存储下来的部分累加即可。
间隔选用 2 的正整数次方是因为 x % 2^n 会被编译器优化为 x & (2^n - 1),将花费周期较长的取模运算转化成花费周期较短的位运算。

#include<cstdio>
#include<cmath>
#pragma warning(disable:4996)
const unsigned smax = 100000001;
double h[smax / 32 + 1], s, t; unsigned T, n, r;
int main() {
	for (unsigned i = 1; i < smax; ++i) {
		s += 1.0 / i;
		if (i % 32 == 0)h[i / 32] = s;
	}
	scanf("%u", &T);
	for (unsigned i = 1; i <= T; ++i) {
		scanf("%u", &n); r = n % 32; t = 0;
		for (unsigned i = 1; i <= r; ++i)t += 1.0 / (n - r + i);
		printf("Case %u: %.10lf\n", i, h[n / 32] + t);
	}
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值