C++でnCrが指定された素数で割り切れるかどうかを判定する方法
3つの変数 N、R、P があるとします。N と R から二項係数 NCR を求め、P は素数とします。このとき、NCR が P で割り切れるかどうかを判定するのが本記事の目的です。例えば、N = 7、R = 2、P = 3 の場合、7C2 = 21 となり、21 は 3 で割り切れるため、結果は true となります。
二項係数は一般的に次の式で表されます。
NCR = N! / (R! × (N − R)!)
ここでルジャンドルの定理(Legendre's Formula)を活用します。この定理を使うと、N!、R!、(N − R)! のそれぞれを割り切る素数 P の最大のべき乗(指数)を求めることができます。NCR が P で割り切れる条件は、N! に含まれる P の指数が、R! と (N − R)! に含まれる P の指数の合計よりも大きくなること、すなわち x(N!) > x(R!) + x((N − R)!) が成り立つことです。
アルゴリズムの仕組み
関数 getPower(n, p) は、ルジャンドルの定理に基づいて n! を割り切る素数 p の指数を計算します。具体的には、n を p で繰り返し割りながらその商を加算していくことで、⌊n/p⌋ + ⌊n/p²⌋ + ⌊n/p³⌋ + … を効率的に求めています。この値を N!、R!、(N − R)! のそれぞれに対して算出し、比較することで割り切れるかどうかを判定できます。
サンプルコード
#include <iostream>
using namespace std;
int getPower(int n, int p) {
int pow = 0;
while (n) {
n /= p;
pow += n;
}
return pow;
}
bool isDivisibleByP(int n, int r, int p) {
// n!、r!、(n - r)! それぞれを割り切る
// p の最大のべき乗を求める
int x1 = getPower(n, p);
int x2 = getPower(r, p);
int x3 = getPower(n - r, p);
if (x1 > x2 + x3)
return true;
return false;
}
int main() {
int n = 7, r = 2, p = 7;
if (isDivisibleByP(n, r, p))
cout << "nCr is divisible by P";
else
cout << "nCr is not divisible by P";
}実行結果
nCr is divisible by P
この例では N = 7、R = 2、P = 7 としています。7C2 = 21 は 7 で割り切れるため、プログラムは「nCr is divisible by P」と出力します。この方法を使えば、階乗の値を直接計算することなく大きな N に対してもオーバーフローを避けながら効率的に判定できます。
-
C++でnに最も近いmの倍数を求めるアルゴリズムと実装方法
問題の概要2つの整数 n と m が与えられたとき、「n に最も近く、かつ m で割り切れる数」を見つけることを考えます。候補が複数存在する場合は、絶対値が最大となる数を返します。また、n が m で完全に割り切れる場合は、そのまま n を返します。例えば、n = 13、m = 4 の場合、出力は 12 になります。13 に近い 4 の倍数としては 12 と 16 が候補ですが、13 との距離が近いのは 12 であるため、これが答えとなります。解決の手順この問題は、次のステップに従って解くことができます。まず q := n / m とし、n1 := m * q を計算しますn * m >
-
【C++】文字列内の「1(0+)1」パターンをすべて検出する方法
文字列の中に「1(0+)1」という形式のパターンが含まれていると仮定します。ここで「(0+)」は、1個以上の「0」が連続して現れることを意味します。この記事では、文字列からこのパターンをすべて検出する方法を解説します。パターン同士が重なり合う場合もカウントの対象とします。なお、対象の文字列はバイナリ文字列であるとは限らず、数字と小文字の英字のみで構成された文字列を扱います。例として、文字列が「1101001」の場合を考えてみましょう。この場合、「101」と「1001」の2つのパターンが見つかります。解決のためのアプローチこの問題は、以下の手順に従って解くことができます。文字列内のすべての文字c