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

C++で配列のすべての部分配列のXORの合計を求める方法


この問題では、n個の整数からなる配列 arr[] が与えられます。私たちの課題は、その配列のすべての部分配列(サブ配列)のXOR値の合計を求めるプログラムを作成することです。

具体的には、まず与えられた配列のすべての部分配列を列挙し、それぞれの部分配列について要素全体のXORを計算し、その値を合計用の変数に加算していきます。

問題例で理解しよう

入力: arr[] = {5, 1, 4}
出力: 19
説明: この配列のすべての部分配列のXORは次のようになります。
XOR {5} = 5
XOR {1} = 1
XOR {4} = 4
XOR {5, 1} = 5^1 = 4
XOR {1, 4} = 1^4 = 5
XOR {5, 1, 4} = 5^1^4 = 0
合計 = 5 + 1 + 4 + 4 + 5 + 0 = 19

単純な解法:すべての部分配列を列挙する

もっとも直感的な解法は、多重ループを使ってすべての部分配列を生成し、各部分配列の要素のXORを計算して合計に加算していく方法です。

しかしこの方法はループの入れ子が必要となり、計算量がO(n³)程度に達するため非常に非効率です。配列のサイズが大きくなると、現実的な時間内に処理を終えることができません。

効率的な解法:プレフィックス(累積XOR)配列の活用

この問題を効率的に解くには、プレフィックス配列(累積XOR配列)を利用するのが有効です。この配列には、配列の先頭からインデックスiまでの要素のXORを格納します。すなわち、

prefixarr[i] = arr[0] ^ arr[1] ^ … ^ arr[i]

このプレフィックス配列を使えば、インデックスiからjまでの範囲の要素のXORは、次の式で簡単に求められます。

XOR(i〜j) = prefixarr[j] ^ prefixarr[i−1] (i ≥ 1 の場合)
XOR(0〜j) = prefixarr[j] (i = 0 の場合)

この公式を応用することで、すべての部分配列のXORを効率よく計算できます。

実装例

以下は、このソリューションの動作を示すC++プログラムです。このコードでは、各ビット位置ごとに「そのビットが立っている要素が奇数個含まれる部分配列」の個数を数え、それに基づいてXORの合計を効率的に算出しています。

#include <iostream>
using namespace std;
int calcSubArrayXORSum(int arr[], int n) {
    int sum = 0;
    int multiplier = 1;
    for (int i = 0; i < 30; i++) {
        int oddCount = 0;
        bool isOdd = 0;
        for (int j = 0; j < n; j++) {
            if ((arr[j] & (1 << i)) > 0)
                isOdd = (!isOdd);
            if (isOdd)
                oddCount++;
        }
        for (int j = 0; j < n; j++) {
            sum += (multiplier * oddCount);
            if ((arr[j] & (1 << i)) > 0)
                oddCount = (n - j - oddCount);
        }
        multiplier *= 2;
    }
    return sum;
}
int main() {
    int arr[] = { 3, 8, 13 };
    int n = sizeof(arr) / sizeof(arr[0]);
    cout<<"Sum of XOR of all subarrays is "<<calcSubArrayXORSum(arr, n);
    return 0;
}

出力

Sum of XOR of all subarrays is 46

実行結果より、配列 {3, 8, 13} のすべての部分配列のXORの合計が46であることが確認できます。

  1. C++で配列の全要素にXOR演算を適用して合計を最小化する方法

    問題の説明サイズNの配列が与えられます。配列の各要素とある整数XとのXOR演算を行ったとき、その結果の合計が最小となるようなXを見つけてください。例として、入力配列が arr[] = {8, 5, 7, 6, 9} の場合、最小合計は 30 になります。各配列要素の2進数表現は次のとおりです。8 : 1000 5 : 0101 7 : 0111 6 : 0110 9 : 1001X = 5 のとき、XOR演算後の各値と合計は以下のようになります。8 ^ 5 = 13 5 ^ 5 = 0 7 ^ 5 = 2 6 ^ 5 = 3 9 ^ 5 = 12 合計 = 30(13 + 0 + 2 + 3

  2. C++でアリコート和(Aliquot Sum)を計算する方法

    本記事では、アリコート和(Aliquot Sum)とは何かを解説します。アリコート和とは、ある数 n の約数のうち、n 自身を除いたすべての約数の総和のことです。例えば、数値が 20 の場合、その約数は (1, 2, 4, 5, 10) となるため、アリコート和は 22 になります。興味深い点として、アリコート和がその数自身と等しくなる場合、その数は「完全数」と呼ばれます。例えば 6 の場合、約数は (1, 2, 3) であり、アリコート和は 1 + 2 + 3 = 6 となるため、6 は完全数です。それでは、以下のアルゴリズムを使ってアリコート和を求める方法を見ていきましょう。アルゴリズムg