C/C++でモジュラー方程式(剰余等式)の解の個数を求めるプログラム
本記事では、モジュラー方程式(剰余等式)に関する興味深い問題を取り上げます。2つの値 A と B が与えられたとき、「(A mod X) = B」を満たす変数 X の候補がいくつあるかを求めるというものです。
例として、A = 26、B = 2 の場合を考えてみましょう。この条件を満たす X の値は {3, 4, 6, 8, 12, 24} の6つとなるため、答えは 6 になります。それでは、処理の流れを理解するためにアルゴリズムを見ていきましょう。
アルゴリズム
possibleWayCount(a, b)
begin
if a = b, then there are infinite solutions
if a < b, then there are no solutions
otherwise div_count := find_div(a, b)
return div_count
endfind_div(a, b)
begin
n := a – b
div_count := 0
for i in range 1 to square root of n, do
if n mode i is 0, then
if i > b, then
increase div_count by 1
end if
if n / i is not same as i and (n / i) > b, then
increase div_count by 1
end if
end if
done
endポイントは、(A mod X) = B が成り立つとき、X は必ず「A − B」の約数であり、かつ B より大きい値でなければならないという性質です。したがって、A − B の約数を効率よく列挙し、B より大きいものだけをカウントすれば答えが求まります。約数の探索は √n まで調べれば十分なので、計算量は O(√n) に抑えられます。
実装例(C++)
#include <iostream>
#include <cmath>
using namespace std;
int findDivisors(int A, int B) {
int N = (A - B);
int div_count = 0;
for (int i = 1; i <= sqrt(N); i++) {
if ((N % i) == 0) {
if (i > B)
div_count++;
if ((N / i) != i && (N / i) > B) //重複して数えないようにする
div_count++;
}
}
return div_count;
}
int possibleWayCount(int A, int B) {
if (A == B) //一致する場合は解が無限に存在する
return -1;
if (A < B) //A < B の場合は解なし
return 0;
int div_count = 0;
div_count = findDivisors(A, B);
return div_count;
}
void possibleWay(int A, int B) {
int sol = possibleWayCount(A, B);
if (sol == -1)
cout << "For A: " << A << " and B: " << B << ", X can take infinite values greater than " << A;
else
cout << "For A: " << A << " and B: " << B << ", X can take " << sol << " values";
}
int main() {
int A = 26, B = 2;
possibleWay(A, B);
}出力結果
For A: 26 and B: 2, X can take 6 values
このプログラムでは、A と B が等しい場合(-1 を返して「無限の解」があることを示す)、A が B より小さい場合(解なしとして 0 を返す)といったエッジケースも適切に処理しています。また、√N までループすることで、約数ペア (i, N/i) の両方を同時にチェックし、同じ約数を二重にカウントしないよう配慮されています。これにより、大きな値に対しても高速に解の個数を求めることができます。
-
C++で10進数を16進数に変換するプログラムの作り方
10進数の数値が入力として与えられたとき、その数値を16進数に変換するのが本記事の目的です。 コンピュータの世界では、16進数は基数16で表現され、10進数は基数10で表現されます。10進数は0〜9の値を使って表されるのに対し、16進数は0〜15の数字を持ちます。そのうち10は「A」、11は「B」、12は「C」、13は「D」、14は「E」、15は「F」として表されます。 10進数から16進数への変換手順 10進数を16進数に変換するには、以下の手順に従います。 まず、与えられた数値を変換先の基数で割ります。たとえば、6789を16進数に変換する場合、基数である16で6789を割り、商を求め
-
C++で10進数を2進数に変換するプログラムの書き方
コンピューターの内部では、すべてのデータが2進数(基数2)として扱われています。一方、私たちが日常的に使う10進数は「0〜9」の数字を組み合わせた基数10の記数法です。この記事では、C++を使って入力された10進数を2進数へ変換するプログラムの考え方と実装方法を解説します。10進数から2進数への変換手順10進数を2進数に変換する基本的な方法は、「2で割った余りを順番に記録していく」ものです。具体的には次の手順で行います。まず、変換したい数値を基数である2で割り、商と余りを求めます。余りが0であればその桁は「0」、1であれば「1」として記録します。続いて、得られた商をさらに2で割り、同じように余