けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

yukicoder No.2417 Div Count

整数の入門にいい感じの問題!

問題概要

正の整数  N と非負整数  K が与えられる。次の条件を満たす正の整数  x の個数を求めよ。

  •  N x で割った余りが  K である

制約

  •  0 \le K \lt N \le 10^{12}

解法

 N x で割ったときの商を  q とおくと、

 N = xq + K

と表せる。これを式変形すると

 xq = N - K

となる。この式は、 x N-K の約数であることを表している。ただし、 K x で割ったときの余りであることから、 x \gt K であることも必要となる。

以上をまとめると、次のことが条件となる。


  •  x N-K の約数である
  •  x \gt K である

逆にこれらを満たすならば、 N x で割ったあまりは  K となる。

コード

結局、 N-K の約数を列挙して、 K より大きいものの個数を数える問題へと帰着された。

計算量は  O(\sqrt{N}) となる。

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

// n の約数を列挙
vector<long long> calc_divisor(long long n) {
    vector<long long> res;
    for (long long i = 1LL; i*i <= n; ++i) {
        if (n % i == 0) {
            res.push_back(i);
            long long j = n / i;
            if (j != i) res.push_back(j);
        }
    }
    sort(res.begin(), res.end());
    return res;
}

int main() {
    long long N, K;
    cin >> N >> K;
    
    // N - K の約数のうち K より大きいものを数える
    const auto &div = calc_divisor(N - K);
    long long res = 0;
    for (auto v : div) if (v > K) ++res;
    cout << res << endl;
}