C++で指定された条件下で変換を繰り返した後の最終的なXとYの値を求める方法
2つの正整数XとYの初期値が与えられているとします。以下のルールに従って値を繰り返し更新し、最終的に残るXとYの値を求める問題を考えてみましょう。
処理のルール
- ステップ1: X = 0 かつ Y = 0 の場合は処理を終了します。そうでなければステップ2へ進みます。
- ステップ2: X ≥ 2Y を満たす場合、X = X − 2Y としてステップ1へ戻ります。満たさない場合はステップ3へ進みます。
- ステップ3: Y ≥ 2X を満たす場合、Y = Y − 2X としてステップ1へ戻ります。どちらの条件も満たさない場合は処理を終了します。
XとYは最大1018という非常に大きな値になり得るため、1回ずつ減算を繰り返す素朴な方法では処理に膨大な時間がかかってしまいます。そこで、同じ操作の繰り返しを剰余演算(%)で一括して行うことで、高速に答えを求められます。
C++による実装例
#include<iostream>
using namespace std;
void alterNumber(long long x, long long y) {
while (true) {
if (x == 0 || y == 0)
break;
if (x >= 2 * y)
x = x % (2 * y);
else if (y >= 2 * x)
y = y % (2 * x);
else
break;
}
cout << "X: " << x << "\n" << "Y: " << y;
}
int main() {
long long x = 12, y = 5;
alterNumber(x, y);
}
出力結果
X: 0 Y: 1
アルゴリズムのポイント
このプログラムの動作は以下の通りです。
- x または y のどちらかが 0 になった時点でループを抜けます。
- x ≥ 2y の場合、「x から 2y を繰り返し引く」操作は x % (2y) を代入することと同じ結果になります。
- y ≥ 2x の場合も同様に、y % (2x) を代入することで複数回の減算をまとめて処理できます。
- x < 2y かつ y < 2x の状態になると、それ以上値が変化しないためループを終了します。
実行例の流れ(x = 12、y = 5 の場合)
- 12 ≥ 2×5 = 10 なので、x = 12 % 10 = 2 となります。
- 次に 5 ≥ 2×2 = 4 なので、y = 5 % 4 = 1 となります。
- さらに 2 ≥ 2×1 = 2 なので、x = 2 % 2 = 0 となります。
- x が 0 になったため処理を終了し、最終結果は X: 0、Y: 1 です。
このように剰余演算を活用することで、1018規模の大きな数でも瞬時に最終値を求めることができます。
-
C++でLCMとHCFが与えられたときにもう一方の数を求める方法
ある数Aと、その最小公倍数(LCM)および最大公約数(HCF/GCD)の値が与えられているとき、もう一方の数Bを求める問題を考えます。例えば、A = 5、LCM = 25、HCF = 4が与えられた場合、もう一方の数は20になります。この問題を解く鍵となるのは、任意の2つの数AとBの間に常に成り立つ次の重要な数学的性質です。$$𝐴∗𝐵=𝐿𝐶𝑀∗𝐻𝐶𝐹$$つまり、「2つの数の積」は「最小公倍数と最大公約数の積」と等しくなります。この式をBについて変形すると、次のようになります。$$𝐵= \frac{LCM*HCF}{A}$$アルゴリズム数A、LCM、
-
行と列の最大値が指定されている場合にPythonで元の行列を復元する方法
問題の概要サイズNの配列AとサイズMの配列B、さらにN×Mの2値行列が与えられているとします。この2値行列では、「1」は元の行列の対応する位置に正の整数が存在していたことを示し、「0」はその位置が元の行列でも0であったことを示します。私たちの課題は、A[i]がi行目の最大要素となり、B[j]がj列目の最大要素となるような元の行列を復元することです。例えば、入力が A = [4, 2, 3]、B = [3, 1, 0, 0, 4, 0, 5] の場合、復元される行列は以下の出力例のようになります。解法のアプローチこの問題を解くためには、以下の手順に従います。N を配列AのサイズとしますM を配列