結果
| 問題 |
No.1240 Or Sum of Xor Pair
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 13:10:28 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 11,218 bytes |
| コンパイル時間 | 765 ms |
| コンパイル使用メモリ | 76,780 KB |
| 実行使用メモリ | 47,744 KB |
| 最終ジャッジ日時 | 2025-05-14 13:11:49 |
| 合計ジャッジ時間 | 9,887 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 29 WA * 1 |
ソースコード
#include <iostream>
#include <vector>
#include <numeric>
// Define the number of bits based on constraints.
// The maximum value of A_i is less than 2^18.
// The maximum value of X is 2^18.
// We need to handle values up to 2^18 - 1, which require 18 bits (indexed 0 to 17).
const int B = 18;
// Trie Node structure
struct TrieNode {
TrieNode* children[2]; // Pointers to child nodes for bit 0 and 1
int count; // Number of elements whose path passes through this node and ends in its subtree
// bit_sum[p] stores the count of elements in this node's subtree that have the p-th bit set.
// Using int (typically 32-bit) is sufficient as max count N=2e5 fits.
int bit_sum[B];
// Constructor initializes node fields
TrieNode() : count(0) {
children[0] = children[1] = nullptr;
// Initialize bit_sum array elements to 0
for(int i=0; i<B; ++i) bit_sum[i] = 0;
}
// Optional Destructor to free memory - generally omitted in competitive programming for speed
// unless memory limits are very strict or multiple test cases run in one process.
// ~TrieNode() {
// delete children[0];
// delete children[1];
// }
};
// Function to insert a value into the trie
// It updates counts and bit sums along the path from the root
void insert(TrieNode* root, int val) {
TrieNode* curr = root;
// Traverse bits from most significant (B-1) down to least significant (0)
for (int k = B - 1; k >= 0; --k) {
// Increment count for the current node, indicating one more element passes through here
curr->count++;
// Update bit sums for the current node based on the bits of 'val'
for (int p = 0; p < B; ++p) {
if ((val >> p) & 1) { // Check if p-th bit of val is set
curr->bit_sum[p]++;
}
}
// Determine the next bit (0 or 1) in the path for 'val'
int bit = (val >> k) & 1;
// If the required child node doesn't exist, create it
if (!curr->children[bit]) {
curr->children[bit] = new TrieNode();
}
// Move to the appropriate child node
curr = curr->children[bit];
}
// After the loop, 'curr' points to the node corresponding to the full path for 'val'.
// Update this final node's count and bit sums as well.
curr->count++;
for (int p = 0; p < B; ++p) {
if ((val >> p) & 1) {
curr->bit_sum[p]++;
}
}
}
// Helper function to calculate SUM (val | A_j) for all A_j in the subtree rooted at 'node'
// This is efficiently computed using precalculated counts and bit sums.
// Called when an entire subtree satisfies the XOR condition relative to 'val' and 'X'.
long long calculate_or_sum(int val, TrieNode* node) {
// If node is null or represents an empty subtree, the sum contribution is 0
if (!node || node->count == 0) {
return 0;
}
long long current_sum = 0;
// Calculate the total sum bit by bit from p=0 to B-1
for (int p = 0; p < B; ++p) {
long long term_count;
// Determine how many elements A_j in the subtree contribute 2^p to the sum for bit p.
// This depends on the p-th bit of 'val'.
if ((val >> p) & 1) {
// If val's p-th bit is 1, then (val | A_j)'s p-th bit is always 1, regardless of A_j's p-th bit.
// Contribution comes from all elements in the subtree.
term_count = node->count;
} else {
// If val's p-th bit is 0, then (val | A_j)'s p-th bit is 1 iff A_j's p-th bit is 1.
// Contribution comes only from elements with p-th bit set.
term_count = node->bit_sum[p];
}
// Add the contribution for bit p: term_count * 2^p
// Use 1LL to ensure the multiplication is done using 64-bit integers to prevent overflow.
current_sum += term_count * (1LL << p);
}
return current_sum;
}
// Structure to bundle the results from the query function:
// count of pairs found and the total sum of their OR values.
struct QueryResult {
long long count; // Number of valid pairs (A_i, A_j) found for a given A_i ('val')
long long total_or_sum; // Sum of (A_i | A_j) for these pairs
};
// Recursive function to query the trie.
// Finds all A_j (already inserted in the trie) such that (val ^ A_j < X)
// and computes the sum of (val | A_j) for these pairs.
// 'node': current node in the trie traversal
// 'val': the value A_i we are currently processing and matching against trie elements
// 'k': current bit position being considered (starts at B-1, goes down to -1)
// 'X': the upper bound for the XOR value (A_i ^ A_j)
QueryResult query_sum(TrieNode* node, int val, int k, int X) {
// Base cases for recursion termination:
// If the current node is null (path doesn't exist),
// or the subtree rooted here is empty (count is 0),
// or we have processed all bits (k < 0).
if (!node || node->count == 0 || k < 0) {
return {0, 0}; // Return zero count and sum
}
QueryResult result = {0, 0}; // Initialize result for the current recursive call
int val_k = (val >> k) & 1; // k-th bit of val (A_i)
int X_k = (X >> k) & 1; // k-th bit of the limit X
TrieNode* child0 = node->children[0]; // Child node corresponding to bit 0
TrieNode* child1 = node->children[1]; // Child node corresponding to bit 1
// The logic branches based on X_k, the k-th bit of the limit X
if (X_k == 1) {
// If X_k is 1, the condition (val ^ Aj < X) can be satisfied in two ways at bit k:
// 1. If the k-th bit of (val ^ Aj) is 0: The XOR is strictly smaller than X up to this bit.
// All elements Aj in the corresponding subtree satisfy the condition. We add their full contribution.
// 2. If the k-th bit of (val ^ Aj) is 1: The XOR matches X up to this bit.
// We need to continue checking the lower bits recursively.
if (val_k == 0) { // k-th bit of val is 0
// Path 1: Consider Aj in child0 (where Aj[k] = 0). XOR bit is 0 ^ 0 = 0.
// Since 0 < X_k = 1, all Aj in child0 satisfy the condition up to bit k.
if (child0) {
long long sum0 = calculate_or_sum(val, child0); // Compute sum for the entire child0 subtree
result.count += child0->count;
result.total_or_sum += sum0;
}
// Path 2: Consider Aj in child1 (where Aj[k] = 1). XOR bit is 0 ^ 1 = 1.
// Since 1 = X_k, we must check lower bits. Recurse on child1.
if(child1) { // Check if child1 exists before recursing
QueryResult res_rec = query_sum(child1, val, k - 1, X);
result.count += res_rec.count;
result.total_or_sum += res_rec.total_or_sum;
}
} else { // k-th bit of val is 1
// Path 1: Consider Aj in child1 (where Aj[k] = 1). XOR bit is 1 ^ 1 = 0.
// Since 0 < X_k = 1, all Aj in child1 satisfy the condition.
if (child1) {
long long sum1 = calculate_or_sum(val, child1); // Compute sum for the entire child1 subtree
result.count += child1->count;
result.total_or_sum += sum1;
}
// Path 2: Consider Aj in child0 (where Aj[k] = 0). XOR bit is 1 ^ 0 = 1.
// Since 1 = X_k, we must check lower bits. Recurse on child0.
if(child0) { // Check if child0 exists before recursing
QueryResult res_rec = query_sum(child0, val, k - 1, X);
result.count += res_rec.count;
result.total_or_sum += res_rec.total_or_sum;
}
}
} else { // X_k == 0
// If X_k is 0, the condition (val ^ Aj < X) can only be potentially satisfied if:
// The k-th bit of (val ^ Aj) is 0. Then it matches X's k-th bit, and we must check lower bits recursively.
// If the k-th bit of (val ^ Aj) is 1, then (val ^ Aj) is already >= X, so the condition is violated.
if (val_k == 0) { // k-th bit of val is 0
// Path 1: Consider Aj in child0 (where Aj[k] = 0). XOR bit is 0 ^ 0 = 0.
// Since 0 = X_k, we must check lower bits. Recurse on child0.
if(child0) { // Check if child0 exists before recursing
QueryResult res_rec = query_sum(child0, val, k - 1, X);
result.count += res_rec.count;
result.total_or_sum += res_rec.total_or_sum;
}
// Path 2: Consider Aj in child1 (where Aj[k] = 1). XOR bit is 0 ^ 1 = 1.
// Since 1 > X_k = 0, the condition is violated. Ignore this path.
} else { // k-th bit of val is 1
// Path 1: Consider Aj in child1 (where Aj[k] = 1). XOR bit is 1 ^ 1 = 0.
// Since 0 = X_k, we must check lower bits. Recurse on child1.
if(child1) { // Check if child1 exists before recursing
QueryResult res_rec = query_sum(child1, val, k - 1, X);
result.count += res_rec.count;
result.total_or_sum += res_rec.total_or_sum;
}
// Path 2: Consider Aj in child0 (where Aj[k] = 0). XOR bit is 1 ^ 0 = 1.
// Since 1 > X_k = 0, the condition is violated. Ignore this path.
}
}
return result; // Return the aggregated count and sum from this level
}
// Optional: Function to delete the entire trie to free allocated memory
void deleteTrie(TrieNode* node) {
if (!node) return;
deleteTrie(node->children[0]);
deleteTrie(node->children[1]);
delete node;
}
int main() {
// Use fast I/O operations
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
int N; // Number of integers
int X; // XOR limit
std::cin >> N >> X;
std::vector<int> A(N); // Vector to store the input integers
for (int i = 0; i < N; ++i) {
std::cin >> A[i];
}
TrieNode* root = new TrieNode(); // Create the root node of the trie
long long total_sum = 0; // Initialize total sum accumulator (use long long for potentially large sums)
// Process each element A[i] of the input array
for (int i = 0; i < N; ++i) {
// Query the trie with A[i]. This finds all A[j] already in the trie (meaning j < i)
// such that A[i] ^ A[j] < X. It also computes the sum of (A[i] | A[j]) for these pairs.
QueryResult result = query_sum(root, A[i], B - 1, X);
// Add the sum obtained from the query to the total sum
total_sum += result.total_or_sum;
// Insert A[i] into the trie. This makes it available for querying against subsequent elements A[k] where k > i.
insert(root, A[i]);
}
// Output the final computed total sum
std::cout << total_sum << std::endl;
// Optional: Deallocate trie memory. Not strictly necessary for typical competitive programming contest submissions
// as OS reclaims memory on program exit, but good practice in general software development.
// deleteTrie(root);
return 0;
}
qwewe