LightOJ1245 Harmonic Number (II) —— 规律

题目链接:https://vjudge.net/problem/LightOJ-1245

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

I was trying to solve problem '1234 - Harmonic Number', I wrote the following code

long long H( int n ) {
    long long res = 0;
    for( int i = 1; i <= n; i++ )
        res = res + n / i;
    return res;
}

Yes, my error was that I was using the integer divisions only. However, you are given n, you have to find H(n) as in my code.

Input

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

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

Output

For each case, print the case number and H(n) calculated by the code.

Sample Input

Output for Sample Input

11

1

2

3

4

5

6

7

8

9

10

2147483647

Case 1: 1

Case 2: 3

Case 3: 5

Case 4: 8

Case 5: 10

Case 6: 14

Case 7: 16

Case 8: 20

Case 9: 23

Case 10: 27

Case 11: 46475828386

题意:

对于一个数n,求出 sigma(n/k), 1<=k<=n。

题解:

1.由于n<=2^31,直接暴力不不可能的。

2.手写一下可发现一个规律, 当 n/i = k时, i的范围为 (n/(k+1), n/k],即有n/k- n/(k+1) 个 i 使得n/i = k。

3.有了上述结论之后,就可以降低暴力程度了,设 m = sqrt(n)。先从1枚举到m,求出n/i的和,这样 [1,m] 这个区间的求值就解决了,还剩 [m+1, n] 这个区间:从m递减枚举到1,求出k*(n/k - n/(k+1))的和,这样就求出了[ n/m, n]的值,当 n/m==m时,即开始下标为m,则区间为[m,n],所以在m的位置重复计算了,需要减去m;当n/m!=m,即n/m>m时,其实下标为m+1,所以区间为 [m+1,n]。

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int mod = 1e9+7;
17 const int MAXM = 1e5+10;
18 const int MAXN = 1e6+10;
19 
20 int main()
21 {
22     int T, n, kase = 0;
23     scanf("%d", &T);
24     while(T--)
25     {
26         scanf("%d", &n);
27         int m = sqrt(n);
28 
29         LL ans = 0;
30         for(int i = 1; i<=m; i++) ans += n/i;
31         for(int i = 1; i<=m; i++) ans += 1LL*i*(n/i - n/(i+1));
32         if(n/m==m) ans -= m;
33         printf("Case %d: %lld
", ++kase, ans);
34     }
35 }
View Code
原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8366296.html