しょぼんブログ

数学の色々とか様々とか

連載 しょぼんコーダー 5 floor(N/i)を楽に列挙する方法

はじめに

正の整数  N を固定します.  i \ge 1として,  \lfloor N/i \rfloor を考えることはよくあります. ここで  \lfloor x \rfloor xを超えない最大の整数です.

 1 \leq i \leq Nを自由に動かすとき,  \lfloor N/i \rfloor のとりうる値の種類の数は \lfloor\sqrt{4N+1}\rfloor -1 \simeq 2 \sqrt{N} です.(A055086 - OEIS

これらの値をすべて列挙する方法で, かなり楽なものを見つけたので今回はこれを紹介します.

コード

まずはc++, pythonコードを見せます.

//CPP
#include <bits/stdc++.h>
using namespace std;

int main(){
    long long N;
    cin >> N;
    long long i = N;
    while (i > 0){
        long long v = N / i;
        long long j = N / (v+1);
        cout << v << endl;
        i = j;
    }
}
#PYTHON
N = int(input())
i = N
while i > 0:
    v = N // i
    j = N // (v+1)
    print(v)
    i = j

 \lfloor N/i \rfloor のとりうる値を小さい順に表示させています.

このとき,  \mathrm{i} \lfloor N/r \rfloor = \mathrm{v}となるような最大の値になって,  \mathrm{j}  \lfloor N/r \rfloor = \mathrm{v}でなくなる最大の値です.

つまり,  (\mathrm{j}, \mathrm{i}]という半開区間 \lfloor N/r \rfloor = \mathrm{v} となるような r区間となります.

証明?

 i=N(すなわち \lfloor \frac{N}{i} \rfloor=1)のときはokです.  \mathrm{v}の次にとりうる値は,  \mathrm{v} + 1以上です.
このとき,  \mathrm{v}+1 \leq \frac{N}{\mathrm{j}} すなわち  \mathrm{j} \leq \frac{N}{\mathrm{v}+1}が成り立ちます.
これを満たす \mathrm{j}の最大値は \lfloor \frac{N}{\mathrm{v}+1} \rfloorです.
よって, 帰納的に最大という条件が満たされます.  i=1のときは,  \mathrm{j} = 0となるのでプログラムが終了します.

例題

E - Fraction Floor Sum

正の整数 Nに対して,  \displaystyle \sum^{N}_{i=1} \left\lfloor \frac{N}{i} \right\rfloorを求める問題です.

この問題は平方分割で解くことができますが, 今のやり方で解いてみます.  \mathrm{i} - \mathrm{j}は,  \lfloor \frac{N}{r} \rfloor = \mathrm{v}となる rの個数であることに注目します.
これは答えに  \mathrm{v} \times (\mathrm{i} - \mathrm{j}) だけ寄与します.

#include <bits/stdc++.h>
using namespace std;

int main(){
    long long N, i, j, v, ans;
    cin >> N;
    i = N;
    ans = 0;
    while (i > 0){
        v = N / i;
        j = N / (v+1);
        ans += v * (i-j);
        i = j;
    }
    cout << ans << endl;
}

練習問題

Codeforces Round #809 (Div.2) D2. Chopping Carrots (Hard Version)

https://codeforces.com/contest/1706/problem/D2

このコードは, この問題の考察中に生まれたものです. メモリ制限が厳しくPythonではあまりオススメできません

関連するもの

次のmaspyさんの記事で,  \lfloor N/i \rfloorがよく出てきます.

Dirichlet 積と、数論関数の累積和 - maspyのHP
https://maspypy.com/dirichlet-%E7%A9%8D%E3%81%A8%E3%80%81%E6%95%B0%E8%AB%96%E9%96%A2%E6%95%B0%E3%81%AE%E7%B4%AF%E7%A9%8D%E5%92%8C