C++で n! mod (k^x) = 0 となる最大の x を求める方法
2つの整数 n と k が与えられたとき、n! mod (k^x) = 0 を満たす最大の x の値を求める問題を考えます。例えば n = 5、k = 2 の場合、答えは 3 になります。これは n! = 120 であり、x の各値に対する剰余を計算すると次のようになるためです。
120 mod 2^0 = 0、120 mod 2^1 = 0、120 mod 2^2 = 0、120 mod 2^3 = 0、120 mod 2^4 = 8、120 mod 2^5 = 24、120 mod 2^6 = 56、120 mod 2^7 = 120
剰余が 0 となる最大の x は 3 であるため、出力は 3 となります。
解法のアプローチ
この問題を効率的に解くには、以下の手順に従います。
- k の平方根を計算し、変数 m に格納する
- i を 2 から m までループさせ、以下の処理を行う
- i が m に達したら、i に k の値を代入する
- k が i で割り切れる間、k を i で割り続ける
- n までの範囲でループを実行し、その商を変数 u に加算する
- 各ループの後に、結果の最小値を保存する
このアルゴリズムの本質は、k を素因数分解し、各素因数 p について「n! に含まれる p の個数」を「k に含まれる p の指数」で割った値の最小値を求める点にあります。n! に含まれる素因数の個数は、ルジャンドルの公式を用いることで効率的に計算できます。
サンプルコード
#include <iostream>
#include <cmath>
using namespace std;
int calculateMaxX(int n, int k) {
int result = n, v, u;
int m = sqrt(k) + 1;
for (int i = 2; i <= m && k > 1; i++) {
if (i == m) {
i = k;
}
for (u = v = 0; k % i == 0; v++) {
k /= i;
}
if (v > 0) {
int t = n;
while (t > 0) {
t /= i;
u += t;
}
result = min(result, u / v);
}
}
return result;
}
int main() {
int n = 5;
int k = 2;
cout << "Maximum value of x is: " << calculateMaxX(n, k);
}出力結果
Maximum value of x is: 3
このプログラムの計算量は、k の素因数分解に O(√k)、各素因数に対するルジャンドルの公式の適用に O(log n) しかかからないため、大きな n や k が与えられた場合でも高速に動作します。
-
C++で配列内の a % b = k を満たすすべてのペア(a, b)を検索する方法
問題の概要配列 A が与えられたとき、その中から a % b = k を満たすすべてのペア(a, b)を見つけることを考えます。たとえば、配列 A = [2, 3, 4, 5, 7]、k = 3 の場合、条件を満たすペアは (7, 4)、(3, 4)、(3, 5)、(3, 7) となります。ここで注意したいのは、(a, b) が順序付きペアであるという点です。つまり (3, 4) と (4, 3) は別々の候補として扱われ、それぞれ剰余演算の結果が k と一致するかどうかが個別に判定されます。解法のアプローチこの問題は、ブルートフォース(総当たり)法によって解くことができます。手順は以下のとお
-
代数式の最大値を求めるC++プログラム:動的計画法による効率的な実装
この記事では、(x₁ + x₂ + … + xₐ) × (y₁ + y₂ + … + y_b) という形式で表される代数式の最大値を求めるC++プログラムを紹介します。合計 (a + b) 個の整数が与えられたとき、その中から a 個を左辺のグループに、残りの b 個を右辺のグループに割り当てるすべての組み合わせを検討し、それぞれの値を計算することで最大値を導き出します。 全組み合わせを総当たりで調べることも可能ですが、ここでは動的計画法(DP)を活用し、より効率的に解く手法を解説します。 アルゴリズム 開始 関数 MaxValue() : 引数: a[]