Card Tricks
Problem Statement
Solution
Problem Analysis
We need to handle three operations on a collection of 32-bit integers:
- Insertion: Add a number and its bit-reversed counterpart
- Retrieval: Find and remove the largest number ≤ mean of current collection
- Flip: Toggle between using original numbers or their bit-reversed versions
Algorithm Design
Data Structures
- Two Multisets: Maintain two collections - one for original values, one for reversed values
- Two Sums: Track sums of both collections for efficient mean calculation
- State Flag: Boolean to track whether we're using original or reversed values
Operations
Insertion (Type 1):
- Compute bit-reversed value of input
- Based on current state, insert original into one multiset and reversed into the other
- Update corresponding sums
Retrieval (Type 2):
- Calculate mean (sum/size) of current collection
- Find largest value ≤ mean using upper_bound
- Remove this value from both collections
- Update sums accordingly
Flip (Type 3):
- Toggle the state flag
Bit Reversal
- For each bit position i (0-15):
- Swap bit i with bit (31-i)
- Preserve the original bit values during swap
Complexity Analysis
- Time: O(log n) per operation (multiset operations)
- Space: O(n) to store all elements
Key Implementation Notes
- Bit Reversal: Must handle 32-bit unsigned integers correctly
- Mean Calculation: Use integer division (floor division)
- Multiset Operations: Ensure O(log n) time complexity for insertions, deletions, and searches
- State Management: Cleanly toggle between original and reversed values
The algorithm efficiently handles all operations while maintaining the required constraints, making it suitable for large input sizes.
cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
const ll LOG = 32;
ll rev(ll x) {
ll t = 0;
for (ll i = 0; i < LOG; i++) {
if ((x >> i) & 1) t |= (1LL << (LOG - i - 1));
}
return t;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(NULL);
ll q = 0;
cin >> q;
vector<ll> bits(LOG);
vector<multiset<ll>> s(2);
bool flip = 0;
while (q--) {
ll t;
cin >> t;
if (t == 1) {
ll v;
cin >> v;
for (ll i = 0; i < LOG; i++) {
if ((v >> i) & 1) bits[i]++;
}
s[flip].insert(v);
s[!flip].insert(rev(v));
} else if (t == 3) {
flip = !flip;
auto c = bits;
for (ll i = 0; i < LOG; i++) {
bits[i] = c[LOG - i - 1];
}
} else if (t == 2) {
ll mean = 0;
for (ll i = 0; i < LOG; i++) {
mean += (1LL << i) * bits[i];
}
mean /= s[flip].size();
ll res = *(--s[flip].upper_bound(mean));
for (ll i = 0; i < LOG; i++) {
if ((res >> i) & 1) bits[i]--;
}
s[flip].erase(s[flip].find(res));
s[!flip].erase(s[!flip].find(rev(res)));
cout << res << "\n";
}
}
return 0;
}
