1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

素因数分解を用いた約数の個数の求め方

Last updated at Posted at 2025-05-01

求め方

素因数分解を用いた約数の個数の求め方を解説します。

約数の個数を求めるために、どのように素因数分解を用いるのかというところですが、以下のことを利用します。

自然数Nを素因数分解した結果が、$N = p^aq^br^c ...$のとき、Nの正の約数の個数は$(a + 1)(b + 1)(c + 1)...$ 個である。

なぜ上記のことが成り立つのかということですが、まず自然数Nは素因数pをa個,素因数qをb個,...もつ数と言えます。
なので、自然数Nの約数は、素因数pをa個以下、素因数qをb個以下持つ数であるということも言えます。
これらの組み合わせの数は、pの指数は$(a+1)$通り、qの指数は$(b+1)$通り、...となるので、これらをかけると約数の個数が求められます。

例として、60の約数の個数を求めるためにこの方法を使ってみましょう。
$60 = 2^2 \times 3 \times 5$ というように60は素因数分解できます。
素因数2,3,5の指数はそれぞれ2,1,1なので、約数の個数は$(2 + 1)(1 + 1)(1 + 1) = 12$個と求められます。
実際に、60の約数の個数は12個です。(1,2,3,4,5,6,10,12,15,20,30,60の12個)

ここまでの内容でわかることは、素因数分解した結果がわかっていれば、約数の個数もわかるということです。。
ここからは、このことを使った問題の解き方について紹介していきます。

例題1

$N!$の約数の個数を数えるのは大変ですが、$N!$を素因数分解した結果は簡単に求められるので、それをつかって約数の個数を計算します。

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

signed main(void){
  int n;
  cin >> n;
  vector<int> prime(1001, 0); //素因数の個数を記録する配列
  for(int i = 2; i <= n; i++){
    int x = i;
    for(int j = 2; j * j <= n; j++){ //xを素因数分解する
      while(x % j == 0){ //割り切れるなら
        prime[j]++; //個数を加算
        x /= j;
      }
    }
    if(x != 1) prime[x]++;
  }
  
  ll ans = 1;
  for(int i = 1; i <= 1000; i++){
    cerr << prime[i] << endl;
    ans *= (prime[i] + 1);
    ans %= 1000000007;
  }
  cout << ans << endl;
}

例題2

この問題では、約数の個数はわかっているので、約数の個数を活かして数を求めます。

約数が9個の数はどのように素因数分解されるかを考えてみます。
約数が9個ということは、言い換えると $N = p^aq^b$ と素因数分解されるとき、$(a + 1)(b + 1) = 9$ であるということです。(9は3つの2以上の整数の積では表せない。)
$(a + 1)(b + 1) = 9$を満たす$(a + 1)$と$(b+1)$の組み合わせを考えてみると、
$a + 1 = 3, b + 1 = 3$
$a + 1 = 9, b + 1 = 1$
$a + 1 = 1, b + 1 = 9$
の3つだとわかります。

このことから、Nを素因数分解したときの結果が次のように表せるとき、約数が9個であるといえます。
$N = p^2q^2, p^8, q^8$
p^8とq^8は同じようなことを意味しているので、$N = p^2q^2, p^8$ と表せると約数が9個といえます。

ここまでのことがわかれば、全探索で答えが求められます。

#include <bits/stdc++.h>
using namespace std; using ll = long long; using ld = long double;

signed main(void){
  ll n;
  cin >> n;
  
  vector<ll> prime; //素数を記録する配列
  prime.push_back(2);
  for(ll i = 3; i < 1000000; i++){ //素数を配列に追加
    bool ok = true; //素数かどうか
    for(ll j = 2; j * j <= i; j++){
      if(i % j == 0){ //割り切れるか判定
        ok = false;
        break;
      }
    }
    if(ok) prime.push_back(i);
  }
  
  ll ans = 0;
  //p^2q^2について
  for(ll p = 0; p < prime.size(); p++){ //(p < q)
    if(prime[p] > 1500) break; //prime[p] > 1500 ならp^2q^2 > N
    for(ll q = p + 1; q < prime.size(); q++){
      ll num = prime[p] * prime[p] * prime[q] * prime[q];
      //p^2q^2で表せる数を計算
      
      if(num <= n){ //N以下なら
        ans++;
      }
      else break;
    }
  }
  //p^8について
  for(ll i = 0; i < prime.size(); i++){
    if(prime[i] > 40) break;
    ll num = 1;
    for(int j = 0; j < 8; j++) num *= prime[i]; //p^8を計算
    if(num <= n){
      ans++;
    }
  }
  cout << ans << endl;
}
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?