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;
}
}