Topics
Given an array of non-negative integers, the loneliness of is the smallest positive integer () such that:
For any two indices where , the following equality holds:
Where represents the bitwise OR operation.
Calculate the loneliness value of array :
- The loneliness is always well-defined because when , there is only one possible subsequence, making the condition trivially satisfied.
- The problem asks for the minimum value of where all overlapping subarrays of length have the same bitwise OR value.
Idea
The problem asks for the smallest window size k
such that the bitwise OR of all subarrays of size k
is the same. We can efficiently find this smallest k
using binary search. For a given k
, we need to check
if all subarrays of size k
have the same bitwise OR value.
Approach 1: Sliding Window
We can use a sliding window of size k
to iterate through all subarrays of length k
. Since bitwise OR is not invertible, we can’t directly subtract elements when the window slides. Instead, we maintain a bitCount
array, which acts like a frequency array but for bits. bitCount[b]
stores the number of elements in the current window that have the bit set.
For each window:
- We update the
bitCount
by removing the leftmost element and adding the rightmost element - We compute the bitwise OR of the current window “manually” using the
bitCount
array in thebits2num
function. IfbitCount[b] > 0
, it means at least one number in the window has the bit set, so the bit of the window’s OR is also set - We compare the current window’s OR with the previous window’s OR. If they are different at any point, we know that this
k
is invalid
If all windows of size k
have the same bitwise OR, the check
function returns true, and we try a smaller k
in the binary search. Otherwise, we try a larger k
.
Time Complexity: due to the binary search (), and the check
function takes
Space Complexity: since the bitCount
array has a fixed size of 32, regardless of the input size
Approach 2: Prefix Sums
Instead of using a sliding window, we can use prefix sums to optimize the check
function. We precompute a 2D prefs
array where prefs[i][j]
stores the number of elements in arr[0...i-1]
that have the bit set.
For a given k
, the check
function iterates through all subarrays of length k
and computes the bitwise OR of each subarray using the prefs
array. The number of ones in the bit of the subarray arr[i-k...i-1]
is given by prefs[i][j] - prefs[i-k][j]
. If this value is greater than 0, it means that at least one number in the subarray has the bit set, so the bit of the subarray’s OR is also set.
The rest of the approach is the same with approach 1: we compare the current window’s OR with the previous window’s OR. If they are different at any point, we know that this k
is invalid
Time Complexity: due to the binary search (), and the check
function takes
Space Complexity: since the prefs
array has a size of
Code
// Approach 1 (Binary search + sliding window)
int bits2num(const vector<int> &bits) {
int num = 0;
for (int i = 0; i < 32; ++i) {
if (bits[i] > 0) {
num |= 1;
}
num <<= 1;
}
return num;
}
bool check(const vector<int> &arr, int k) {
int n = (int)arr.size();
vector<int> bitCount(32, 0);
// initial bit counts for the first k elements
for (int i = 0; i < k; i++) {
for (int b = 0; b < 32; b++) {
if (arr[i] & (1 << b)) {
bitCount[31 - b]++;
}
}
}
// Compute the OR for the first window
int prevOR = bits2num(bitCount);
// Slide the window from index k to n-1
for (int r = k; r < n; r++) {
// Remove arr[r - k] from the window
for (int b = 0; b < 32; b++) {
if (arr[r - k] & (1 << b)) {
bitCount[31 - b]--;
}
}
// Add arr[r] to the window
for (int b = 0; b < 32; b++) {
if (arr[r] & (1 << b)) {
bitCount[31 - b]++;
}
}
// Compute the OR for the current window
int currOR = bits2num(bitCount);
// If this window's OR differs, fail
if (currOR != prevOR) {
return false;
}
}
// If all windows of size k had the same OR, return true
return true;
}
void solve() {
int n;
cin >> n;
vector<int> arr(n);
for (int i = 0; i < n; ++i)
cin >> arr[i];
int lo = 1;
int hi = n;
ll ans = hi;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (check(arr, mid)) {
ans = mid;
hi = mid - 1;
} else {
lo = mid + 1;
}
}
cout << ans << endl;
}
// Approach 2 (Binary search + prefix sums)
bool check(int n, const vector<vi> &prefs, int k) {
int prev = 0;
for (int i = k; i <= n; ++i) {
int curr = 0;
for (int j = 0; j < 32; ++j) {
int ones = prefs[i][j] - prefs[i - k][j];
if (ones > 0) {
curr |= (1 << j);
}
}
if (i > k and prev != curr)
return false;
prev = curr;
}
return true;
}
void solve() {
int n;
cin >> n;
vector<int> arr(n);
vector<vi> prefs(n + 1, vi(32, 0));
for (int i = 0; i < n; ++i) {
cin >> arr[i];
int curr = arr[i];
for (int j = 0; j < 32; ++j) {
prefs[i + 1][j] = prefs[i][j] + (curr & 1);
curr >>= 1;
}
}
int lo = 1;
int hi = n;
ll ans = hi;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (check(n, prefs, mid)) {
ans = mid;
hi = mid - 1;
} else {
lo = mid + 1;
}
}
cout << ans << endl;
}