LeetCode Entry

2818. Apply Operations to Maximize Score

29.03.2025 hard 2025 kotlin rust

Multiply k numbers with max prime factor count stack

2818. Apply Operations to Maximize Score hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/942

Problem TLDR

Multiply k numbers with max prime factor count #hard #monotonic_stack

Intuition

Didn’t solve without the hints. Take maximum values first. We can take all subarrays where this value has the maximum prime factors count (and is leftmost). Count subarrays = count to the left * count to the right Use the monotonic stack to track left and right values: always add to the stack, remove all elements less than the current.

To build prime numbers: maintain boolean array up to 100_000, for every number that is prime mark all its multiplications as not prime.

To multiply res = current ^ range % mod use exponentiation technique: x^e = x^(2*e/2) = (x^2)^(e/2) = (x * x) ^ (e / 2) = x^(e/2)*x^(e/2) if e % 2 == 0, or x * x^(e/2) * x^(e/2) if not.

Approach

  • we can inline the exponent function
  • we can skip computing prime numbers, as O(nsqrt(n)) accepted

Complexity

  • Time complexity: \(O(nlog(n))\) or O(nsqrt(n))

  • Space complexity: \(O(n)\)

Code


    fun maximumScore(nums: List<Int>, k: Int): Int {
        val m = 1_000_000_007L; var res = 1L; var k = 1L * k
        val scores = nums.map { var x = it; var c = 0; var p = 2;
            while (p * p < x && x > 0) { if (x % p < 1) { c++; while (x % p == 0) x /= p }; p++ }
            c + if (x > 1) 1 else 0 }
        val left = IntArray(nums.size) { -1 }; val right = IntArray(nums.size) { nums.size }
        val l = ArrayList<Int>(); val r = ArrayList<Int>()
        for (i in nums.indices) { val j = nums.size - 1 - i
            while (l.size > 0 && scores[l.last()] < scores[i]) l.removeLast()
            while (r.size > 0 && scores[r.last()] <= scores[j]) r.removeLast()
            if (l.size > 0) left[i] = l.last(); if (r.size > 0) right[j] = r.last()
            l += i; r += j }
        for (i in nums.indices.sortedBy{ -nums[it] }) {
            val range = 1L * (i - left[i]) * (right[i] - i)
            var x = 1L * nums[i]; var e = 1L * min(range, k)
            while (e > 0) { if (e % 2 > 0) res = (res * x) % m; e /= 2; x = (x * x) % m }
            k -= range; if (k < 1L) break }
        return res.toInt()
    }


    pub fn maximum_score(nums: Vec<i32>, mut k: i32) -> i32 {
        let scores: Vec<_> = nums.iter().map(|&n| { let mut x = n; let mut c = 0; let mut p = 2;
            while p * p < x && x > 0 { if x % p < 1 { c += 1; while x % p == 0 { x /= p }}; p += 1 }
            c + ((x > 1) as i32) }).collect();
        let (n, m, mut res) = (nums.len(), 1_000_000_007, 1);
        let (mut left, mut right, mut l, mut r) = (vec![-1; n], vec![n as i64; n], vec![], vec![]);
        for i in 0..n { let j = n - 1 - i;
            while l.len() > 0 && scores[l[l.len() - 1]] < scores[i] { l.pop(); }
            while r.len() > 0 && scores[r[r.len() - 1]] <= scores[j] { r.pop(); }
            if l.len() > 0 { left[i] = l[l.len() - 1] as i64 }; if r.len() > 0 { right[j] = r[r.len() - 1] as i64 }
            l.push(i); r.push(j) }
        let mut idx: Vec<_> = (0..n).collect(); idx.sort_unstable_by_key(|&i| -nums[i]);
        for i in idx { let range = (i as i64 - left[i]) * (right[i] - i as i64);
            let (mut x, mut e) = (nums[i] as i64, range.min(k as i64));
            while e > 0 { if e & 1 > 0 { res = (res * x) % m }; e /= 2; x = (x * x) % m }
            k -= range as i32; if k < 1 { break }
        }; res as _
    }


    int maximumScore(vector<int>& a, int k) {
        int m = 1e9+7, n = size(a), res = 1; vector<int> sc(n), sl, sr, l(n, -1), r(n, n);
        for(int i = 0; i < n; ++i) {
            int x = a[i], c = 0; for (int p = 2; p * p <= x; p++)
                if (x % p == 0) { c++; while (x % p == 0) x /= p; }
            sc[i] = c + (x > 1);
        }
        for (int i = 0, j; i < size(a); i++) {
            for (j = size(a) - 1 - i; size(sl) && sc[sl.back()] < sc[i]; sl.pop_back());
            for (; size(sr) && sc[sr.back()] <= sc[j]; sr.pop_back());
            if (size(sl)) l[i] = sl.back(); sl.push_back(i);
            if (size(sr)) r[j] = sr.back(); sr.push_back(j);
        }
        vector<int> idx(size(a)); iota(begin(idx), end(idx), 0);
        sort(begin(idx), end(idx), [&](int i, int j) { return a[i] > a[j]; });
        for (int i : idx) {
            long range = 1LL * (i - l[i]) * (r[i] - i);
            long x = 1LL * a[i],  e = min(1L * k, range);
            for (; e; e /= 2, x = (x * x) % m) if (e & 1) res = (res * x) % m;
            if ((k -= range) < 1) break;
        }
        return res;
    }