LeetCode 7023操作使得分最大

发布时间 2023-08-13 22:35:22作者: cherish-lgb

7023. 操作使得分最大

题目描述:一个数字的质数分数为其质因数个数;给定一个长度为\(n\)的正整数数组nums和正整数k,可以进行k次如下操作:

  • 选择一个之前没有选择过的非空子数组subnums
  • subnums中选择一个质数分数最大的元素x,如果多个元素质数分数相同且最大,选择下标最小的一个
  • 将得分乘以x

初始时得分为1;求经过k次操作后的最大得分,对\(10^9 + 7\)取模

思路:比较明显,每次选的x越大最终得分越高,所以我们需要每次选择最大的x,然后枚举所有包含x的子数组中,x的质数分数最大且下标最小的数量,假设为m,则对答案的贡献就为\(x^{\min(m, k)}\)。假设scoresnums所对应的质数分数数组,那么对于一个下标\(i\),要满足上述条件,则需要求最小的\(j\)满足对于任意的\(j \leq r < i\)\(scores_i > scores_r\);求最大的\(k\),满足对于任意的\(i \leq r \leq k\)\(scores_i \geq scores_r\);则此时\(m = (i - j + 1) \times (k - i + 1)\);根据上述描述,显然可以使用单调栈求解scores数组。

时间复杂度:\(O(nlogn)\)

空间复杂度:\(O(n)\)

参考代码:

class Solution {
public:
    int maximumScore(vector<int>& nums, int k) {
        const int MX = 100005;
        const int mod = 1000'000'007;
        vector<int> primeCount(MX, 0);
        for (int i = 2; i < MX; ++i) {
            if (primeCount[i] != 0) {
                continue;
            }
            for (int j = i; j < MX; j += i) {
                primeCount[j]++;
            }
        }
        int n = nums.size();
        vector<int> scores(n, 0);
        vector<int> index(n);
        for (int i = 0; i < n; ++i) {
            scores[i] = primeCount[nums[i]];
            index[i] = i;
        }
        sort(index.begin(), index.end(), [&](const int a, const int b) {
            return nums[a] > nums[b];
        });
        vector<int> left(n, -1), right(n, n);
        stack<int> s;
        for (int i = 0; i < n; ++i) {
            while (!s.empty() && scores[s.top()] < scores[i]) {
                int pop = s.top();
                s.pop();
                right[pop] = i;
            }
            if (!s.empty()) {
                left[i] = s.top();
            }
            s.push(i);
        }
        function<int(int, int)> quickPow = [](int a, int p) -> int {
            int ret = 1;
            while (p > 0) {
                if ((p & 1) == 1) {
                    ret = 1ll * ret * a % mod;
                }
                p >>= 1;
                a = 1ll * a * a % mod;
            }
            return ret;
        };
        int res = 1;
        for (auto idx : index) {
            long long cur = 1ll * (idx - left[idx]) * (right[idx] - idx);
            if (cur > k) {
                cur = k;
            }
            res = 1ll * res * quickPow(nums[idx], cur) % mod;
            k -= cur;
            if (k == 0) {
                break;
            }
        }
        return res;
    }
};