The simplest way is to try every possible subsequence of length 2 * k (keeping original order), compute the bitwise OR of the first k elements and the OR of the last k elements, then take the XOR of those two ORs. Because k is small and n is at most 400, this brute-force enumerative approach is easy to implement and straightforward to reason about.
⏰ Time complexity:O(C(n, 2*k) * k) – We enumerate every combination of 2*k indices (there are C(n,2k) of them) and for each we do O(k) work to compute the two ORs.
🧺 Space complexity:O(2*k) – We store the current combination of indices and a few scalars while computing ORs.
We can avoid enumerating all C(n,2k) subsequences by precomputing, for every prefix and every possible OR value, whether it’s possible to pick exactly t elements from that prefix that produce that OR. Do the same for suffixes (or equivalently reverse the array and compute the same DP). Then, for each split point between prefix and suffix (i.e., choose how many original elements belong to the prefix), combine possible left OR values (from prefix DP) with possible right OR values (from suffix DP) and maximize their XOR. This trades combinatorial enumeration for DP over the OR-value space, which is small (W = 128) because numbers are small (<= 127).
Let W be the number of possible OR-values (we use W = 128 since nums[i] < 128).
Build dp_prefix[i][t] = set of OR-values achievable by picking exactly t elements from the first i elements of nums (0 <= i <= n).
Build dp_suffix by reversing nums and computing the same DP; dp_suffix[s][t] then represents achievable ORs using t elements from the last s elements of the original array.
For every split i where the prefix uses the first i elements and the suffix uses the last n - i elements, check all or1 in dp_prefix[i][k] and or2 in dp_suffix[n - i][k] and update answer with or1 ^ or2.
Return the maximum XOR found.
This DP is efficient because W is small (128), so iterating over OR-values is cheap. We use sets for OR-values in languages where convenient and boolean 3D arrays where sets are less convenient.
classSolution {
public:int maxValue(vector<int>& nums, int k) {
int n = nums.size();
constint W =128; // possible OR values: 0..127
auto build = [&](const vector<int>& a) {
int m = a.size();
// dp[i][t][v] : using first i elements, can we pick t elements with OR == v?
vector<vector<vector<char>>> dp(m +1, vector<vector<char>>(k +1, vector<char>(W, 0)));
dp[0][0][0] =1;
for (int i =0; i < m; ++i) {
for (int t =0; t <= k; ++t) {
for (int v =0; v < W; ++v) {
if (!dp[i][t][v]) continue;
// not take
dp[i +1][t][v] =1;
// take
if (t < k) dp[i +1][t +1][v | a[i]] =1;
}
}
}
return dp;
};
auto dp1 = build(nums);
reverse(nums.begin(), nums.end());
auto dp2 = build(nums); // dp2 on reversed array
int ans =0;
for (int i = k; i <= n - k; ++i) {
for (int v1 =0; v1 < W; ++v1) {
if (!dp1[i][k][v1]) continue;
for (int v2 =0; v2 < W; ++v2) {
if (!dp2[n - i][k][v2]) continue;
ans = max(ans, v1 ^ v2);
}
}
}
return ans;
}
};
import java.util.*;
classSolution {
publicintmaxValue(int[] nums, int k) {
int n = nums.length;
finalint W = 128;
boolean[][][] dp1 = buildDP(nums, k, W);
// reverse array for suffix DP reverse(nums);
boolean[][][] dp2 = buildDP(nums, k, W);
int ans = 0;
for (int i = k; i <= n - k; ++i) {
for (int v1 = 0; v1 < W; ++v1) {
if (!dp1[i][k][v1]) continue;
for (int v2 = 0; v2 < W; ++v2) {
if (!dp2[n - i][k][v2]) continue;
ans = Math.max(ans, v1 ^ v2);
}
}
}
return ans;
}
privateboolean[][][]buildDP(int[] a, int k, int W) {
int m = a.length;
boolean[][][] dp =newboolean[m + 1][k + 1][W];
dp[0][0][0]=true;
for (int i = 0; i < m; ++i) {
for (int t = 0; t <= k; ++t) {
for (int v = 0; v < W; ++v) {
if (!dp[i][t][v]) continue;
dp[i + 1][t][v]=true;
if (t < k) dp[i + 1][t + 1][v | a[i]]=true;
}
}
}
return dp;
}
privatevoidreverse(int[] a) {
int i = 0, j = a.length- 1;
while (i < j) {
int tmp = a[i]; a[i]= a[j]; a[j]= tmp;
i++; j--;
}
}
}
classSolution {
funmaxValue(nums: IntArray, k: Int): Int {
val n = nums.size
val W = 128val dp1 = buildDP(nums.copyOf(), k, W)
nums.reverse()
val dp2 = buildDP(nums, k, W)
var ans = 0for (i in k..n - k) {
for (v1 in0 until W) {
if (!dp1[i][k][v1]) continuefor (v2 in0 until W) {
if (!dp2[n - i][k][v2]) continue ans = maxOf(ans, v1 xor v2)
}
}
}
return ans
}
privatefunbuildDP(a: IntArray, k: Int, W: Int): Array<Array<BooleanArray>> {
val m = a.size
val dp = Array(m + 1) { Array(k + 1) { BooleanArray(W) } }
dp[0][0][0] = truefor (i in0 until m) {
for (t in0..k) {
for (v in0 until W) {
if (!dp[i][t][v]) continue dp[i + 1][t][v] = trueif (t < k) dp[i + 1][t + 1][v or a[i]] = true }
}
}
return dp
}
}
from typing import List
classSolution:
defmaxValue(self, nums: List[int], k: int) -> int:
n = len(nums)
W =128defbuild(a: List[int]):
m = len(a)
# dp[i][t] = set of OR-values possible using first i elements picking t elements dp = [ [set() for _ in range(k+1)] for _ in range(m+1) ]
dp[0][0].add(0)
for i in range(m):
for t in range(k+1):
for v in dp[i][t]:
dp[i+1][t].add(v)
if t < k:
dp[i+1][t+1].add(v | a[i])
return dp
dp1 = build(nums)
nums.reverse()
dp2 = build(nums)
ans =0for i in range(k, n - k +1):
left_set = dp1[i][k]
right_set = dp2[n - i][k]
ifnot left_set ornot right_set:
continuefor v1 in left_set:
for v2 in right_set:
ans = max(ans, v1 ^ v2)
return ans
impl Solution {
pubfnmax_value(nums: Vec<i32>, k: i32) -> i32 {
let n = nums.len();
let k = k asusize;
let w =128usize;
fnbuild(a: &Vec<i32>, k: usize, w: usize) -> Vec<Vec<Vec<u8>>> {
let m = a.len();
letmut dp =vec![vec![vec![0u8; w]; k+1]; m+1];
dp[0][0][0] =1;
for i in0..m {
for t in0..=k {
for v in0..w {
if dp[i][t][v] ==0 { continue; }
dp[i+1][t][v] =1;
if t < k {
let nv = v | (a[i] asusize);
dp[i+1][t+1][nv] =1;
}
}
}
}
dp
}
letmut a = nums.clone();
let dp1 = build(&a, k, w);
a.reverse();
let dp2 = build(&a, k, w);
letmut ans =0i32;
for i in k..=n - k {
for v1 in0..w {
if dp1[i][k][v1] ==0 { continue; }
for v2 in0..w {
if dp2[n - i][k][v2] ==0 { continue; }
ans = ans.max((v1 ^ v2) asi32);
}
}
}
ans
}
}
⏰ Time complexity:O(n * k * W + n * W^2) – Building the prefix/suffix DP costs O(n * k * W) and combining prefix/suffix OR-values costs O(n * W^2) where W is the OR-value range (here W = 128).
🧺 Space complexity:O(n * k * W) – The prefix and suffix DP tables each store O(n * k * W) boolean states.
Method 3 – Bottom-up DP (Iterative, with rolling updates)#
The bottom-up DP implements the same reachable-OR idea as Method 2 but builds the DP iteratively from left to right (prefixes) and right to left (suffixes). By using iterative updates (rolling from i to i+1) we make the transition explicit and can optionally optimize memory when full per-index snapshots are not required.
Initialize dp_prefix[0][0] = {0} (only OR 0 with 0 picks). Iteratively compute dp_prefix[i+1] from dp_prefix[i] by adding the option to take or skip nums[i].
Similarly compute dp_suffix by iterating from the end of the array backward.
Store for each prefix-length i the boolean mask dp_prefix[i][t][v] indicating if OR v is achievable with t picks. Do the same for suffixes.
Combine prefix and suffix OR-values for each valid split i (where i elements are available to the left and n-i to the right) and maximize v1 ^ v2 over all v1 in dp_prefix[i][k] and v2 in dp_suffix[n-i][k].
This method is equivalent in semantics to Method 2 but written as an explicit iterative DP. It also makes it straightforward to replace the full dp_prefix array with a rolling window if you only need the previous state.
classSolution {
public:int maxValue(vector<int>& nums, int k) {
int n = nums.size();
constint W =128;
// build prefix DP iteratively
vector<vector<vector<char>>> dp_pref(n +1, vector<vector<char>>(k +1, vector<char>(W, 0)));
dp_pref[0][0][0] =1;
for (int i =0; i < n; ++i) {
for (int t =0; t <= k; ++t) {
for (int v =0; v < W; ++v) {
if (!dp_pref[i][t][v]) continue;
// skip nums[i]
dp_pref[i+1][t][v] =1;
// take nums[i]
if (t < k) dp_pref[i+1][t+1][v | nums[i]] =1;
}
}
}
// build suffix DP iteratively from right to left
vector<vector<vector<char>>> dp_suf(n +1, vector<vector<char>>(k +1, vector<char>(W, 0)));
dp_suf[0][0][0] =1;
for (int i = n-1; i >=0; --i) {
int idx = n -1- i; // number of elements processed in suffix so far
for (int t =0; t <= k; ++t) {
for (int v =0; v < W; ++v) {
if (!dp_suf[idx][t][v]) continue;
// skip nums[i]
dp_suf[idx+1][t][v] =1;
// take nums[i]
if (t < k) dp_suf[idx+1][t+1][v | nums[i]] =1;
}
}
}
int ans =0;
for (int i = k; i <= n - k; ++i) {
for (int v1 =0; v1 < W; ++v1) {
if (!dp_pref[i][k][v1]) continue;
for (int v2 =0; v2 < W; ++v2) {
if (!dp_suf[n - i][k][v2]) continue;
ans = max(ans, v1 ^ v2);
}
}
}
return ans;
}
};
import java.util.*;
classSolution {
publicintmaxValue(int[] nums, int k) {
int n = nums.length;
finalint W = 128;
boolean[][][] dpPref =newboolean[n+1][k+1][W];
dpPref[0][0][0]=true;
for (int i = 0; i < n; ++i) {
for (int t = 0; t <= k; ++t) {
for (int v = 0; v < W; ++v) {
if (!dpPref[i][t][v]) continue;
dpPref[i+1][t][v]=true;
if (t < k) dpPref[i+1][t+1][v | nums[i]]=true;
}
}
}
boolean[][][] dpSuf =newboolean[n+1][k+1][W];
dpSuf[0][0][0]=true;
for (int i = n-1; i >= 0; --i) {
int idx = n-1-i;
for (int t = 0; t <= k; ++t) {
for (int v = 0; v < W; ++v) {
if (!dpSuf[idx][t][v]) continue;
dpSuf[idx+1][t][v]=true;
if (t < k) dpSuf[idx+1][t+1][v | nums[i]]=true;
}
}
}
int ans = 0;
for (int i = k; i <= n - k; ++i) {
for (int v1 = 0; v1 < W; ++v1) {
if (!dpPref[i][k][v1]) continue;
for (int v2 = 0; v2 < W; ++v2) {
if (!dpSuf[n - i][k][v2]) continue;
ans = Math.max(ans, v1 ^ v2);
}
}
}
return ans;
}
}
classSolution {
funmaxValue(nums: IntArray, k: Int): Int {
val n = nums.size
val W = 128val dpPref = Array(n+1) { Array(k+1) { BooleanArray(W) } }
dpPref[0][0][0] = truefor (i in0 until n) {
for (t in0..k) {
for (v in0 until W) {
if (!dpPref[i][t][v]) continue dpPref[i+1][t][v] = trueif (t < k) dpPref[i+1][t+1][v or nums[i]] = true }
}
}
val dpSuf = Array(n+1) { Array(k+1) { BooleanArray(W) } }
dpSuf[0][0][0] = truefor (i in n-1 downTo 0) {
val idx = n-1-i
for (t in0..k) {
for (v in0 until W) {
if (!dpSuf[idx][t][v]) continue dpSuf[idx+1][t][v] = trueif (t < k) dpSuf[idx+1][t+1][v or nums[i]] = true }
}
}
var ans = 0for (i in k..n-k) {
for (v1 in0 until W) {
if (!dpPref[i][k][v1]) continuefor (v2 in0 until W) {
if (!dpSuf[n - i][k][v2]) continue ans = maxOf(ans, v1 xor v2)
}
}
}
return ans
}
}
from typing import List
classSolution:
defmaxValue(self, nums: List[int], k: int) -> int:
n = len(nums)
W =128 dp_pref = [ [set() for _ in range(k+1)] for _ in range(n+1) ]
dp_pref[0][0].add(0)
for i in range(n):
for t in range(k+1):
for v in dp_pref[i][t]:
dp_pref[i+1][t].add(v)
if t < k:
dp_pref[i+1][t+1].add(v | nums[i])
dp_suf = [ [set() for _ in range(k+1)] for _ in range(n+1) ]
dp_suf[0][0].add(0)
for i in range(n-1, -1, -1):
idx = n-1-i
for t in range(k+1):
for v in dp_suf[idx][t]:
dp_suf[idx+1][t].add(v)
if t < k:
dp_suf[idx+1][t+1].add(v | nums[i])
ans =0for i in range(k, n - k +1):
left = dp_pref[i][k]
right = dp_suf[n - i][k]
ifnot left ornot right:
continuefor v1 in left:
for v2 in right:
ans = max(ans, v1 ^ v2)
return ans
impl Solution {
pubfnmax_value(nums: Vec<i32>, k: i32) -> i32 {
let n = nums.len();
let k = k asusize;
let w =128usize;
letmut dp_pref: Vec<Vec<Vec<u8>>>=vec![vec![vec![0u8; w]; k+1]; n+1];
dp_pref[0][0][0] =1;
for i in0..n {
for t in0..=k {
for v in0..w {
if dp_pref[i][t][v] ==0 { continue; }
dp_pref[i+1][t][v] =1;
if t < k {
let nv = v | (nums[i] asusize);
dp_pref[i+1][t+1][nv] =1;
}
}
}
}
letmut dp_suf: Vec<Vec<Vec<u8>>>=vec![vec![vec![0u8; w]; k+1]; n+1];
dp_suf[0][0][0] =1;
for i in (0..n).rev() {
let idx = n-1-i;
for t in0..=k {
for v in0..w {
if dp_suf[idx][t][v] ==0 { continue; }
dp_suf[idx+1][t][v] =1;
if t < k {
let nv = v | (nums[i] asusize);
dp_suf[idx+1][t+1][nv] =1;
}
}
}
}
letmut ans =0i32;
for i in k..=n - k {
for v1 in0..w {
if dp_pref[i][k][v1] ==0 { continue; }
for v2 in0..w {
if dp_suf[n - i][k][v2] ==0 { continue; }
ans = ans.max((v1 ^ v2) asi32);
}
}
}
ans
}
}
⏰ Time complexity:O(n * k * W + n * W^2) – Iteratively building prefix and suffix DP tables costs O(n * k * W) and combining OR-values across splits costs O(n * W^2).
🧺 Space complexity:O(n * k * W) – We store boolean DP tables for prefixes and suffixes in this straightforward bottom-up implementation.