E - チームの組み合わせ / Team Combinations Editorial by admin Editorial for printing
GLM 5.2 (High)Overview
This problem asks us to find the total number of ways to choose subsets from two groups such that, if the XOR sums of the chosen elements from the first and second groups are \(X\) and \(Y\) respectively, then \(X + Y = S\).
Analysis
A naive approach to solve this problem would require checking \(2^{2N}\) combinations in total, as there are \(2^N\) possible subsets to choose from the first group and \(2^N\) from the second group. For \(N=50\), this is an astronomical number and will not run within the time limit.
Here, we consider dividing the problem into two independent subproblems. Let \(X\) be the XOR sum of the chosen subset from the first group, and \(Y\) be the XOR sum of the chosen subset from the second group. Our goal is to find the total number of ways to choose subsets such that the pair \((X, Y)\) satisfies \(X + Y = S\).
If we know “the number of ways to choose a subset from the first group such that its XOR sum is \(x\)”, we can multiply it by “the number of ways to choose a subset from the second group such that its XOR sum is \(S - x\)” to calculate the number of valid pairs.
Since the maximum value of the elements is less than \(2^{20}\), the XOR sum will be an integer between \(0\) and \(2^{20}-1\) inclusive. Therefore, if we can calculate “the number of ways to get each XOR sum” for each group, we can efficiently find the overall answer.
Algorithm
We can use Dynamic Programming (DP) to find the distribution of XOR sums for each group.
DP Definition:
dpA[x]: The total number of ways to choose elements from the first group such that their XOR sum is \(x\).dpB[y]: The total number of ways to choose elements from the second group such that their XOR sum is \(y\).
DP Initialization:
- When no elements are chosen, the XOR sum is \(0\). Thus, we initialize
dpA[0] = 1anddpB[0] = 1.
- When no elements are chosen, the XOR sum is \(0\). Thus, we initialize
DP Transitions:
- We process the elements one by one, updating the DP table by considering two cases: “not choosing the element” and “choosing the element”.
- When adding an element \(A_i\), if the current XOR sum is \(j\), choosing \(A_i\) transitions the XOR sum to \(j \oplus A_i\) (where \(\oplus\) denotes the XOR operation).
- Specifically, we prepare a new array
nextAand performnextA[j] += dpA[j](for not choosing) andnextA[j \oplus A[i]] += dpA[j](for choosing). - By performing these transitions for all elements, we obtain the final distribution of XOR sums. The same process applies to the second group.
Calculating the Answer:
- When fixing the XOR sum of the first group to \(x\), the XOR sum of the second group must be \(y = S - x\).
- If \(y\) is in the range from \(0\) to \(2^{20}-1\), we can add
dpA[x] * dpB[S - x]toans. Summing this over all possible \(x\) yields the final answer.
Complexity
- Time Complexity: \(O(N \cdot 2^{20})\). This is because there are \(N\) DP updates, and each update processes \(2^{20}\) states. Since we do this for two groups, the total number of loop iterations is approximately \(2 \cdot 50 \cdot 2^{20} \approx 10^8\), which easily runs within the time limit.
- Space Complexity: \(O(2^{20})\). This is because we allocate two arrays of size \(2^{20}\) for the DP tables.
Implementation Points
Since the DP table size is as large as \(2^{20} = 1048576\), we can use
std::vector’s copy andswapoperations to efficiently update and swap the arrays.When calculating \(X + Y = S\) at the end, if \(y = S - x\) is negative or greater than or equal to \(2^{20}\), it is an unreachable XOR sum for the second group. We must exclude these cases using conditional branches to prevent out-of-bounds array access.
Source Code
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int N;
long long S;
if (!(cin >> N >> S)) return 0;
vector<int> A(N), B(N);
for (int i = 0; i < N; ++i) cin >> A[i];
for (int i = 0; i < N; ++i) cin >> B[i];
const int SZ = 1 << 20;
vector<long long> dpA(SZ, 0), nextA(SZ, 0);
dpA[0] = 1;
for (int i = 0; i < N; ++i) {
copy(dpA.begin(), dpA.end(), nextA.begin());
for (int j = 0; j < SZ; ++j) {
nextA[j ^ A[i]] += dpA[j];
}
swap(dpA, nextA);
}
vector<long long> dpB(SZ, 0), nextB(SZ, 0);
dpB[0] = 1;
for (int i = 0; i < N; ++i) {
copy(dpB.begin(), dpB.end(), nextB.begin());
for (int j = 0; j < SZ; ++j) {
nextB[j ^ B[i]] += dpB[j];
}
swap(dpB, nextB);
}
long long ans = 0;
for (int x = 0; x < SZ; ++x) {
long long y = S - x;
if (y >= 0 && y < SZ) {
ans += dpA[x] * dpB[y];
}
}
cout << ans << "\n";
return 0;
}
This editorial was generated by or-glm5.2-high.
posted:
last update: