二重ループでも、$O(n^2)$ になるとは限らない。
for (int d = 1; d <= N; d++) { // d は間隔(公差)
for (int x = d; x <= N; x += d) { // d, 2d, 3d, ... (N を超えない範囲)
// floor(N/d) 回呼ばれる
}
}
全体のループ回数はだいたい $\displaystyle n + \frac{n}{2} + \frac{n}{3} + \cdots \frac{n}{n} = n(1 + \frac{1}{2} + \frac{1}{3} + \cdots + \frac{1}{n}) = O(n \log n)$
調和級数ループが出てくるところ
$0 < d, x \leq M,\ d \mid x$ を満たす $(d, x)$ の全列挙(計算量は $O(M \log M)$)
$x, y\geq 1,\ xy \leq M$ を満たす $(x,y)$ の全列挙(計算量は $O(M \log M)$)
Rust での実装
$H_n = 1 + 1/2 + \cdots 1/n$ を調和数という。
$H_n = O(\log n)$ である。