LeetCode 7023操作使得分最大
7023. 操作使得分最大
题目描述:一个数字的质数分数为其质因数个数;给定一个长度为\(n\)的正整数数组nums
和正整数k
,可以进行k
次如下操作:
- 选择一个之前没有选择过的非空子数组
subnums
- 从
subnums
中选择一个质数分数最大的元素x
,如果多个元素质数分数相同且最大,选择下标最小的一个 - 将得分乘以
x
初始时得分为1;求经过k
次操作后的最大得分,对\(10^9 + 7\)取模
思路:比较明显,每次选的x
越大最终得分越高,所以我们需要每次选择最大的x
,然后枚举所有包含x
的子数组中,x
的质数分数最大且下标最小的数量,假设为m
,则对答案的贡献就为\(x^{\min(m, k)}\)。假设scores
是nums
所对应的质数分数数组,那么对于一个下标\(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;
}
};
作者:cherish.
出处:https://home.cnblogs.com/u/cherish-/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。