C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++でgcd(A, B)がBとなるペア(A ≤ N、B ≤ N)の個数を数える方法

問題の概要

入力として整数 N が与えられます。求めるのは、1 ≤ A ≤ N かつ 1 ≤ B ≤ N を満たし、最大公約数 GCD(A, B)B と一致するようなすべてのペア (A, B) の個数です。つまり、「ペアの最大公約数が B そのものになる」組み合わせをすべて数え上げます。

入出力の例

入力: N = 5

出力: gcd(A, B) が B となるペア (A ≤ N, B ≤ N) の個数 ― 10

説明:

(1,1), (2,1), (3,1), (4,1), (5,1),
(2,2), (3,3), (4,2), (4,4), (5,5) の合計 10 個

入力: N = 50

出力: gcd(A, B) が B となるペア (A ≤ N, B ≤ N) の個数 ― 207

説明:

(1,1), (2,1), (3,1), (4,1), (5,1) … (50,1)
(2,2), (3,3), (4,4) … (50,50)

このほかにも (4,2)、(6,3)、(8,2)、(8,4)、…、(50,25) のようなペアが存在し、合計は 207 個となります。

解法のアプローチ

この問題を解くには、単純な全探索(ナイーブな方法)と効率的な方法など、複数のアプローチが考えられます。まずはナイーブなアプローチから見ていきましょう。

  • 整数 N を入力として受け取ります。
  • 関数 GCD(int A, int B) は 2 つの整数を受け取り、A と B の最大公約数を返します。再帰的に計算を行います。
  • A または B のどちらかが 0 なら、もう一方を返します。両者が等しければ、いずれかの値を返します。A > B であれば GCD(A−B, B) を、B の方が大きければ GCD(A, B−A) を返します。これを繰り返すことで gcd の値が得られます。
  • 関数 count_pairs(int N) は N を受け取り、ペア (A, B) において B が gcd と一致し、両方が [1, N] の範囲に収まるようなペアの個数を返します。
  • ペアの個数を数えるため、初期値 count = 0 を用意します。
  • 各ペアの値について、A に対応する for ループ(i = 1 から i = N まで)と、B に対応する入れ子の for ループ(j = 1 から j = N まで)を実行します。
  • ペア (i, j) を作成して GCD(i, j) に渡し、結果が j と一致したら count をインクリメントします。
  • 両方のループが終了した時点で、count を結果として返します。

効率的なアプローチ

GCD(a, b) = b が成り立つということは、a が必ず b の倍数であることを意味します。したがって、N 以下の b(1 ≤ b ≤ N)の倍数はすべて条件を満たすペアを作ります。ある数 i については、N 以下の i の倍数の個数、すなわち floor(N / i) 個がカウント対象になります。

  • 関数 Count_pairs(int N) は N を受け取り、条件を満たすペアの個数を返します。
  • 初期値として count = 0 を用意します。
  • 一時変数 temp = N、i = 1 とします。
  • while (i ≤ N) のループ内で以下の処理を行います。
  • 各 i について、商の値が同じ区間の末尾 j = N / temp を求めます。
  • 現在の区間に含まれるペアの数は temp × (j − i + 1) なので、これを count に加算します。
  • i = j + 1 とし、次の B の候補へ進みます。
  • 次回の反復に備えて temp = N / i を更新します。
  • while ループが終了したら、count を結果として返します。

実装例(ナイーブなアプローチ)

#include <iostream>
using namespace std;
int GCD(int A, int B){
   if (A == 0){
      return B;
   }
   if (B == 0){
      return A;
   }
   if (A == B){
      return A;
   }
   if (A > B){
      return GCD(A-B, B);
   }
   return GCD(A, B-A);
}
int count_pairs(int N){
   int count = 0;
   for(int i=1; i<=N; i++){
      for(int j = 1; j<=N; j++){
         if(GCD(i, j)==j){
            count++;
         }
      }
   }
   return count;
}
int main(){
   int N = 4;
   cout<<"gcd(A, B) が B となるペア (A <= N, B <= N) の個数: "<<count_pairs(N);
   return 0;
}

出力

上記のコードを実行すると、次の出力が得られます。

gcd(A, B) が B となるペア (A <= N, B <= N) の個数: 8

実装例(効率的なアプローチ)

#include <bits/stdc++.h>
using namespace std;
int Count_pairs(int N){
   int count = 0;
   int temp = N;
   int i = 1;
   while(i <= N){
      int j = N / temp;
      count += temp * (j - i + 1);
      i = j + 1;
      temp = N / i;
   }
   return count;
}
int main(){
   int N = 4;
   cout<<"gcd(A, B) が B となるペア (A <= N, B <= N) の個数: "<<Count_pairs(N);
   return 0;
}

出力

上記のコードを実行すると、次の出力が得られます。

gcd(A, B) が B となるペア (A <= N, B <= N) の個数: 8
  1. C++でXORが0になる配列内のペアの数を求める方法

    n個の要素を含む配列が与えられたとき、XOR(排他的論理和)の計算結果が0になるペアの数を求めることを考えます。ペア(x, y)のXORが0になるのは、x = y が成り立つ場合、すなわち2つの値が等しいときだけです。これは「同じ数値同士のXORは必ず0になる」というビット演算の基本的な性質によるものです。解法のアプローチこの問題は、次の手順で解くことができます。まず、配列を昇順にソートします。ソート後は同じ値どうしが隣り合って並ぶため、連続する2つの要素を比較し、等しければカウントを1つ増やします。すべての要素が同じ値である場合、末尾側のペアがカウントから漏れる可能性があります。そこで、配列

  2. 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 と一致するかどうかが個別に判定されます。解法のアプローチこの問題は、ブルートフォース(総当たり)法によって解くことができます。手順は以下のとお