#3574
Hard Algorithms Maximize subarray gcd score
Array Math Enumeration Number Theory
24.7% acceptance
Feb 25, 2026
46
4
You are given array nums and integer k (at most k operations, each doubles one element once).
Score of subarray = length * GCD(all elements). Return maximum score.
Solution
Rust
Time O(n²)
Space O(n)
impl Solution {
pub fn max_gcd_score(nums: Vec<i32>, k: i32) -> i64 {
let n = nums.len();
let k = k as usize;
fn gcd(a: i64, b: i64) -> i64 {
if b == 0 { a } else { gcd(b, a % b) }
}
let mut ans = 0i64;
// For each subarray [i..j], the optimal strategy is:
// - GCD of subarray determines the score multiplied by length
// - Doubling an element x increases GCD only if all others share gcd with 2x
// - Key insight: doubling element x changes gcd(subarray) only if x is the bottleneck
// In practice, for a subarray, we can double at most k elements.
// The GCD can increase by factor of 2 if we double all elements that have an odd factor.
//
// Simplified observation: For any subarray, the GCD g of original values divides all nums[i].
// Doubling nums[i] changes it to 2*nums[i]. The GCD after doubling some subset S is:
// gcd of {2*nums[i] for i in S, nums[i] for i not in S}
// = gcd of {nums[i] for all i} * possible_factor if all elements in subarray are doubled
// or keep same g if not all are doubled.
// Actually: if we double ALL elements: gcd becomes 2*g, score = len * 2*g
// If we double SOME elements: gcd may or may not change.
//
// For subarray of length L: if L <= k, we can double all elements, gcd = 2*g, score = 2*g*L
// If L > k: we can only double k of the L elements. Doubling k of them won't make gcd = 2*g
// unless each undoubled element already has factor 2.
//
// More precisely: gcd(subarray after doubling subset S) = gcd of the modified values.
// Let g = gcd(nums[i..j]). Write nums[i] = g * a[i]. Then gcd(a[i]) = 1.
// After doubling subset S: gcd = g * gcd({2*a[i] for i in S, a[i] for i not in S}).
// Since gcd(a) = 1, and we double some subset, the resulting gcd is:
// If not all are doubled: gcd(2*a[i], a[j]) divides a[j], so gcd is 1 or 2.
// It's 2 iff all a[j] (undoubled) are even. But gcd(a[i])=1 means not all even unless...
// Actually: for gcd to be 2, all undoubled a[j] must be even AND all doubled 2*a[i] must be even (trivially).
// If some a[j] is odd and j not in S, then gcd is odd (=1). So gcd=1, score = g*L.
//
// Optimal: for each subarray [i,j] of length L:
// g = gcd(nums[i..=j])
// score_no_double = L * g
// If L <= k: can double all -> score = 2 * L * g
// Else: can we double all odd-a[j] elements? Count of elements where nums[j]/g is odd.
// If that count <= k: score = 2 * L * g
// Else: score = L * g
for i in 0..n {
let g = 0i64;
let mut odd_count = 0usize; // count of nums with (nums/gcd) odd
// When gcd changes, odd_count needs to be recomputed
// We'll track g incrementally and recompute odd_count when needed
let mut cur_gcd = 0i64;
for j in i..n {
let v = nums[j] as i64;
let prev_gcd = cur_gcd;
cur_gcd = gcd(cur_gcd, v);
let _ = g;
let len = (j - i + 1) as i64;
// Recompute odd_count when gcd changes
if cur_gcd != prev_gcd {
// Recompute odd_count for subarray [i..=j]
odd_count = (i..=j).filter(|&r| (nums[r] as i64 / cur_gcd) % 2 == 1).count();
} else {
// Just add nums[j]: check if nums[j]/cur_gcd is odd
if (v / cur_gcd) % 2 == 1 {
odd_count += 1;
}
}
let score = if odd_count <= k {
2 * len * cur_gcd
} else {
len * cur_gcd
};
if score > ans { ans = score; }
}
}
ans
}
}