C++で指定範囲内の2整数から最大XOR値を求めるアルゴリズム
問題の概要
範囲 [L, R] が与えられたとき、この範囲内から2つの整数を選び、そのXOR(排他的論理和)が考えられるすべての組み合わせの中で最大となるようにする問題です。
例として、L = 1、R = 21 が与えられた場合を考えてみましょう。このとき出力は 31 になります。
これは、15 XOR 16 = 31 となり、範囲内のどの2整数の組み合わせよりも大きなXOR値になるためです。
アルゴリズム
この問題は、全組み合わせを総当たりで調べなくても、ビット演算の性質を使えば効率的に解くことができます。
1. L ^ R の値を計算する 2. その値の最上位ビット(MSB)の位置を求める 3. MSBの位置から下位に向かってすべてのビットを1にした値が答えになる
なぜこの方法で正しいのか
L ^ R の最上位ビットが立っているということは、その桁において L と R の値が異なることを意味します。つまり、その桁では範囲内に「0」と「1」の両方が存在します。したがって、MSBの位置から下のすべてのビットについて、片方の数では0、もう片方の数では1となるような2つの整数を範囲内から必ず選ぶことができ、結果としてすべてのビットが1になった値(最大XOR)が得られます。
C++での実装例
#include <bits/stdc++.h>
using namespace std;
int getMaxXOR(int L, int R){
// L と R のXORを計算
int LXR = L ^ R;
int msbPos = 0;
// 最上位ビットの位置を求める
while (LXR) {
msbPos++;
LXR >>= 1;
}
// MSBの位置から下のビットをすべて1にする
int maxXOR = 0;
int two = 1;
while (msbPos--) {
maxXOR += two;
two <<= 1;
}
return maxXOR;
}
int main(){
int L = 1;
int R = 21;
cout << "Result = " << getMaxXOR(L, R) << endl;
return 0;
}実行結果
上記のプログラムをコンパイルして実行すると、次の出力が得られます。
Result = 31
計算量
このアルゴリズムの時間計算量は O(log R) であり、範囲内の全ペアを調べる O((R-L)^2) の総当たり法と比べて非常に高速です。特に R が大きい場合に有効な手法といえます。
-
C++で配列内のペアから得られる最大のビット単位AND(論理積)値を求めるアルゴリズム
問題文 n個の正の整数からなる配列が与えられます。この中から任意の2つの要素を選んだペアについて、ビット単位AND(論理積)の最大値を求めるのが本問題です。 例 入力配列が {10, 12, 15, 18} の場合、ビット単位ANDの最大値は 12 となります。これは 12 (1100) と 15 (1111) のANDを取った結果 1100(= 12)が最も大きいためです。 アルゴリズム ビット単位ANDでは、両方のビットが1である場合にのみ、結果のその桁が1になります。この性質を利用すると、以下のような貪欲法で効率よく最適解を求められます。 最上位ビット(MSB)から順に、そのビッ
-
C++で配列内の最小XOR値ペアを求める方法
問題概要整数の配列が与えられたとき、配列内のペアの中でXOR値が最小となるペアを見つける問題です。例例えば、配列 arr[] = {10, 20, 30, 40} が与えられた場合を考えてみましょう。各ペアのXOR値を計算すると以下のようになります。(10 ^ 20) = 30(10 ^ 30) = 20(10 ^ 40) = 34(20 ^ 30) = 10(20 ^ 40) = 60(30 ^ 40) = 54この結果から、最小のXOR値は 10 であり、これはペア「20 と 30」に対応することがわかります。アルゴリズム最もシンプルなアプローチは、全探索(ブルートフォース)です。配列から