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

gcd(P[i], i) > 1 となるインデックスの個数がちょうど K になる順列を C++ で求める方法

問題の概要

2つの整数 NK が与えられたとします。このとき、範囲 [1, N] の整数からなる順列 P のうち、gcd(P[i], i) > 1 を満たすインデックス(1始まり)の個数がちょうど K 個になるものを見つける必要があります。

例えば、N = 4、K = 3 の場合、出力は [1, 2, 3, 4] となります。なぜなら、gcd(1, 1) = 1、gcd(2, 2) = 2、gcd(3, 3) = 3、gcd(4, 4) = 4 であり、gcd(P[i], i) > 1 となるのはインデックス 2、3、4 の 3 箇所だからです。

解法の考え方

この問題には、次のような重要な性質があります。

  • gcd(i, i+1) = 1(連続する整数は互いに素)
  • gcd(1, i) = 1(1 と任意の数の最大公約数は常に 1)
  • gcd(i, i) = i(同じ数同士の最大公約数はその数自身)

これらの性質から、K の最大値は N − 1 であることが分かります。まず P[i] = i となる恒等順列を考えると、gcd(P[i], i) > 1 を満たすインデックスの個数は N − 1 個になります(i = 1 のときだけ gcd(1, 1) = 1 となるため)。

ここからカウントを調整するには、要素の入れ替え(スワップ)を利用します。

  • 1 以外の連続する 2 要素を入れ替える → 該当するインデックスの個数がちょうど 2 減る
  • 1 と他の要素を入れ替える → 該当するインデックスの個数がちょうど 1 減る

この仕組みを使えば、目的の K に合わせてカウントを段階的に減らしていくことができます。

C++ での実装例

#include<iostream>
using namespace std;

void findPermutation(int n, int k) {
    // 解が存在しないケースを除外
    if (k >= n || (n % 2 == 0 && k == 0)) {
        cout << -1;
        return;
    }

    int P[n + 1];
    // 恒等順列で初期化(カウントは n - 1 からスタート)
    for (int i = 1; i <= n; i++)
        P[i] = i;

    int count = n - 1;
    for (int i = 2; i < n; i += 2) {
        if (count - 1 > k) {
            // 連続する 2 要素を入れ替えてカウントを 2 減らす
            swap(P[i], P[i + 1]);
            count -= 2;
        } else if (count - 1 == k) {
            // 1 と入れ替えてカウントを 1 減らす
            swap(P[1], P[i]);
            count--;
        } else
            break;
    }

    for (int i = 1; i <= n; i++)
        cout << P[i] << " ";
}

int main() {
    int n = 5, k = 3;
    cout << "Permutation is: ";
    findPermutation(n, k);
}

実行結果

Permutation is: 2 1 3 4 5

コードのポイント

  • 不可能なケースの判定: k ≥ n の場合や、N が偶数かつ k = 0 の場合は解が存在しないため -1 を出力します。
  • 初期化: 恒等順列 P[i] = i から開始し、この時点でのカウントは N − 1 です。
  • カウント調整: 目標の K まで、連続要素のスワップ(−2)と 1 とのスワップ(−1)を組み合わせて調整します。

このアルゴリズムの計算量は O(N) であり、非常に効率的に答えを求められます。

  1. C++で「x + 桁の合計 = n」を満たす数xを見つける方法

    この記事では、ある整数 n が与えられたとき、「x + x の各桁の合計 = n」という条件を満たす数 x を求める問題を解説します。例として、n = 21 の場合を考えてみましょう。このとき答えは x = 15 となります。なぜなら、15 の各桁の合計は 1 + 5 = 6 であり、15 + 6 = 21 となって、与えられた n と一致するからです。解き方のアプローチこの問題はシンプルな方法で解くことができます。1 から n まで順番に数を調べていき、それぞれの数について「その数自身 + 各桁の合計」が n と等しくなるかどうかを確認します。条件を満たす数が見つかった時点で処理を終了し、そ

  2. Pythonでgcd(N^M, N&M)が最大になる正の整数Mを求める方法

    問題概要 正の整数 N が与えられたとき、M < N を満たす正の整数 M のうち、gcd(N^M, N&M)(N^M はビットごとのXOR、N&M はビットごとのAND)が最大になるものを見つけます。そして、得られた最大のgcdの値を返します。 例えば、入力が 20 の場合、出力は 31 になります。 解法のポイント この問題の鍵は、XORとANDのビットレベルでの性質にあります。あるビット位置において、N と M のビットが異なれば XOR では 1 になり、両方とも 1 のときにだけ AND が 1 になります。 N のビット長を k とすると、M として「N の各ビッ