LightOJ1245 - Harmonic Number (II) (数论分块)

Description

题目大意:
高效计算函数H(n)的值。

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

思路

有个叫做数论分块的东西,可以计算考虑含有\(\left\lfloor\frac{n}{i}\right\rfloor\)的求和式子(n为常数)。
对于任意的i,我们要找到一个最大j,使得\(\left\lfloor\frac{n}{i}\right\rfloor=\left\lfloor\frac{n}{j}\right\rfloor\)
事实上,\(j=\left\lfloor\frac{n}{\left\lfloor\frac{n}{i}\right\rfloor}\right\rfloor\)
证明:

\[\left\lfloor\frac{n}{i}\right\rfloor \le \frac{n}{i} \]

\[\left\lfloor\frac{n}{\left\lfloor\frac{n}{i}\right\rfloor}\right\rfloor \ge \left\lfloor\frac{n}{\frac{n}{i}}\right\rfloor \]

\[j=\left\lfloor\frac{n}{\left\lfloor\frac{n}{i}\right\rfloor}\right\rfloor \ge i \]

用放缩易证\(\left\lfloor\frac{n}{i}\right\rfloor=\left\lfloor\frac{n}{j}\right\rfloor\)

所以这题就好办了,将n划分为若干区间[i,j]求和即可。
时间复杂度不清楚,代码跑了2000ms

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <string>
#include <stack>
#include <deque>
#include <cmath>
#include <iomanip>
#include <cctype>

#define endl '\n'
#define IOS std::ios::sync_with_stdio(0);
#define pb push_back
#define mp make_pair
#define seteps(N) fixed << setprecision(N) 

typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/

#define INF 0x3f3f3f3f
const int N = 1e8 + 10;
const double eps = 1e-8;



int main() {
    IOS;
    int t;
    cin >> t;
    int cas = 0;
    while(t--) {
        ll n;
        cin >> n;
        ll cur = 1;
        ll ans = 0;
        while(cur <= n) {
            ll tar = n / (n / cur);
            ans += (tar - cur + 1) * (n / cur);
            cur = tar + 1;
        }
        cout << "Case " << ++cas << ": " << ans << endl;
    }
}
posted @ 2020-06-19 00:18  limil  阅读(119)  评论(0编辑  收藏  举报