素因数分解を上手に活用しよう!
問題概要
正の整数 が与えられる。
の正の約数の個数を 1000000007 で割った余りを求めよ。
制約
考えたこと
「約数の個数」をまともに考察する場合には、素因数分解が役にたつことが多い。一般に正の整数 が
と素因数分解できるとき、 の正の約数の個数は
と表せるのだ。
よって、この問題は「 の素因数分解を求める」問題へと帰着された。
の素因数分解
まず、 より、
の素因数分解に登場する素数は 1000 以下であることがわかる。そこで、1000 以下の素数を列挙して、各素数
について、「
の素因数分解における
の指数」を求めることにしよう。
それはつまり、「 が
で何回割り切れるか」を求められれば良い。これは数学 IA の教科書にも載っている有名問題だ。次のように求められる。
これを求める計算量は となる。
よって、全体の計算量は、 以下の素数の個数を
として、
と評価できる。
コード
#include <bits/stdc++.h> using namespace std; const int MOD = 1000000007; vector<int> Era(int n) { vector<bool> isprime(n, true); vector<int> res; isprime[0] = false; isprime[1] = false; for (int i = 2; i < n; ++i) isprime[i] = true; for (int i = 2; i < n; ++i) { if (isprime[i]) { res.push_back(i); for (int j = i*2; j < n; j += i) isprime[j] = false; } } return res; } int main() { long long N, res = 1; cin >> N; // N 以下の素数 vector<int> primes = Era(N + 1); for (auto p : primes) { // 各素数 p について、N! を何回割り切るかを求める long long exp = 0, N2 = N; while (N2) { exp += N2 / p; N2 /= p; } // res に (exp + 1) をかける res = res * (exp + 1) % MOD; } cout << res << endl; }