C++で算術数(約数の平均が整数になる数)を判定する方法
算術数とは
算術数(Arithmetic Number)とは、その数のすべての正の約数の平均(相加平均)が整数になる数のことです。つまり、ある数 n について「約数の総和 ÷ 約数の個数」が割り切れる場合、その n は算術数であると定義されます。
具体例で確認してみましょう。
入力 : n = 6 出力 : YES 説明 : 約数は 1, 2, 3, 6 約数の総和 = 1 + 2 + 3 + 6 = 12 約数の個数 = 4 約数の総和 ÷ 約数の個数 = 12 / 4 = 3(整数なので算術数)
なお、素数 p の場合、約数は 1 と p の2つだけなので平均は (1 + p) / 2 となります。p が奇素数であれば必ず整数になるため、すべての奇素数は算術数であることも分かります。
判定アルゴリズム
算術数かどうかの判定は、以下の手順で行います。
- 約数の総和を計算し、変数 sum に格納する。
- 約数の総個数を求める。
- 約数の総和を約数の総個数で割った余りが 0 になるかどうかを確認する。
- 余りが 0 であれば「YES」を出力し、そうでなければ「NO」を出力する。
C++での実装例
以下の実装では、エラトステネスの篩を利用して約数の個数を効率よく求め、約数の総和は素因数分解に基づく公式(約数関数)で計算しています。
#include <bits/stdc++.h>
using namespace std;
void SieveOfEratosthenes(int n, bool prime[], bool primesquare[], int a[]);
int countDivisors(int n);
int sumofFactors(int n);
int main(){
int n = 46;
int divcount = countDivisors(n);
int divsum = sumofFactors(n);
if(divsum % divcount == 0){
cout << "YES";
}
else
cout << "NO";
return 0;
}
// エラトステネスの篩で素数表と素数の平方表を作成
void SieveOfEratosthenes(int n, bool prime[], bool primesquare[], int a[]){
for (int i = 2; i <= n; i++)
prime[i] = true;
for (int i = 0; i <= (n * n + 1); i++)
primesquare[i] = false;
prime[1] = false;
for (int p = 2; p * p <= n; p++) {
if (prime[p] == true) {
for (int i = p * 2; i <= n; i += p)
prime[i] = false;
}
}
int j = 0;
for (int p = 2; p <= n; p++) {
if (prime[p]) {
a[j] = p;
primesquare[p * p] = true;
j++;
}
}
}
// 約数の個数を求める関数
int countDivisors(int n){
if (n == 1)
return 1;
bool prime[n + 1], primesquare[n * n + 1];
int a[n];
SieveOfEratosthenes(n, prime, primesquare, a);
int ans = 1;
for (int i = 0;; i++) {
if (a[i] * a[i] * a[i] > n)
break;
int cnt = 1;
while (n % a[i] == 0){
n = n / a[i];
cnt = cnt + 1;
}
ans = ans * cnt;
}
if (prime[n])
ans = ans * 2;
else if (primesquare[n])
ans = ans * 3;
else if (n != 1)
ans = ans * 4;
return ans;
}
// 約数の総和を求める関数
int sumofFactors(int n){
int res = 1;
for (int i = 2; i <= sqrt(n); i++) {
int count = 0, curr_sum = 1;
int curr_term = 1;
while (n % i == 0) {
count++;
n = n / i;
curr_term *= i;
curr_sum += curr_term;
}
res *= curr_sum;
}
if (n >= 2)
res *= (1 + n);
return res;
}実行結果
YES
このプログラムでは n = 46 を判定しています。46 の約数は 1, 2, 23, 46 の4つで、総和は 72。72 ÷ 4 = 18 となり平均が整数になるため、「YES」が出力されます。
まとめ
算術数の判定は「約数の総和が約数の個数で割り切れるか」というシンプルな条件で実現できます。約数の個数と総和を効率的に計算することで、大きな数に対しても高速に判定が可能です。競技プログラミングや数論の学習において、約数関数やエラトステネスの篩と組み合わせて活用できるテーマです。
-
C++で可変数の引数(可変長引数)を扱う方法
プログラミングをしていると、引数の個数があらかじめ決まっていない関数、つまり呼び出しのたびに異なる数のパラメータを受け取れる関数が必要になる場面があります。C/C++ではこのような状況に対応する仕組みが用意されており、要件に応じて可変個の引数を受け取る関数を自由に定義できます。以下に、そのような関数の定義例を示します。 int func(int, ... ) { . . . } int main() { func(1, 2, 3); func(1, 2, 3, 4); } 注目すべきは、関数func()の最後の引数が省略記号(ピリオド3つの「...」)になってい
-
C++のCHAR_BITとは?意味と使い方を解説
CHAR_BITは、char型が持つビット数を表すマクロです。C++では「limits.h」ヘッダーファイル(C++では<climits>)で宣言されており、一般的な環境では1バイトが8ビットであることを示します。このマクロを利用することで、移植性の高いコードを書くことができます。環境に依存せずにchar型のビット数を取得できるため、ビット演算やデータサイズの計算に役立ちます。CHAR_BITの使用例以下は、C++でCHAR_BITを使用したサンプルコードです。CHAR_BITとsizeofを組み合わせてint型の全ビット数を求め、整数値を2進数形式で出力しています。#includ