C++で部分配列(サブアレイ)のXORを求める方法【前処理で高速化】
問題概要
この問題では、整数配列 arr[] と、配列上の範囲 L から R を指定するクエリが与えられます。目的は、L から R までの部分配列(サブアレイ)のXORを計算して出力することです。
具体例で問題を確認してみましょう。
入力: array = {1, 4, 5, 7, 2, 9}、L = 1、R = 5
出力: 13
説明: 求める値は 4 ^ 5 ^ 7 ^ 2 ^ 9 の計算結果である 13 です。
解決のための考え方
この問題を効率的に解くには、次のXORの性質を利用します。
- 同じビット位置の複数のビットをXORするとき、1 の個数が奇数であれば結果は 1、偶数であれば結果は 0 になる。
この性質をもとに、1 の出現回数を記録する二次元配列 count を作成します。count[i][j] は、「先頭から j 番目までの部分配列 arr[0..j] における、i ビット目の 1 の個数」を表します。
この count 配列を使えば、部分配列 arr[L..R] の各ビット位置における 1 の個数は、次の式で求められます。
count[i][R] − count[i][L−1]
あるビット位置 i における 1 の個数が奇数であれば、答えの i ビット目は 1 にセットされます。最終的なXORの結果は、セットされた各ビット i に対応する 2 の累乗(1 << i)をすべて加算することで得られます。
この前処理を行っておけば、各クエリに対して最大32ビット分の判定だけでXORを求められるため、クエリのたびに範囲内を逐次計算する方法に比べて大幅に高速化できます。
実装例(C++プログラム)
#include <bits/stdc++.h>
using namespace std;
void preProcessArray(int arr[], int n, vector<vector<int> >& cnt) {
int i, j;
for (i = 0; i < 32; i++) {
cnt[i][0] = 0;
for (j = 0; j < n; j++) {
if (j > 0) {
cnt[i][j] = cnt[i][j - 1];
}
if (arr[j] & (1 << i))
cnt[i][j]++;
}
}
}
int findXORofSubArray(int L, int R, const vector<vector<int> > count) {
int result = 0;
int noOfOnes;
int i, j;
for (i = 0; i < 32; i++) {
noOfOnes = count[i][R] - ((L > 0) ? count[i][L - 1] : 0);
if (noOfOnes & 1) {
result+=(1 << i);
}
}
return result;
}
int main(){
int arr[] = { 1, 4, 5, 7, 2, 9 };
int n = sizeof(arr) / sizeof(arr[0]);
vector<vector<int> > count(32, vector<int>(n));
preProcessArray(arr, n, count);
int L = 1;
int R = 5;
cout<<"The XOR of SubArray: "<<findXORofSubArray(L, R, count);
return 0;
}
実行結果
The XOR of SubArray: 13
-
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」に対応することがわかります。アルゴリズム最もシンプルなアプローチは、全探索(ブルートフォース)です。配列から
-
C++のstatic_castとは?基本からエラー例まで解説
static_castとはstatic_castは、C++における通常の型変換(キャスト)を行うための演算子です。暗黙的な型変換を担う役割もあり、明示的に記述して呼び出すこともできます。例えば、floatからintへの変換、charからintへの変換などが代表的な使用例です。また、継承関係にあるクラス同士(基底クラスと派生クラス)のポインタ変換にも利用できます。C言語風のキャスト((int)x のような書き方)と比べると、static_castは意図が明確になり、コンパイラによる型チェックも働くため、より安全で可読性の高いコードになります。基本的な使用例以下は、float型の値をint型に変換