思路
首先转换思路。要结果最大,因为nums可以随便排,那就是询问次数最多的地方放最大值,次多的放次大值,以此类推。
下面就需要统计询问中,各个位置询问次数,然后次数和值分别排序,按要求相乘累加即是答案;
一种朴素的思想是在每个询问中,遍历首到尾,依次增加中间出现位置的次数,但会超时
vector<int> count(n, 0);
for(auto x : requests) {
for(int i = x[0]; i <= x[1]; i++) {
count[i]++;
}
}
而降低这一过程时间复杂度,可以用到前缀和的思想,每次询问,将首位+1,末位的下一位-1,表明这个区间内的数都被询问了一次,之后求每个位置的前缀和。这其实就是差分的思想。
至于为什么求前缀和,下面分情况讨论下,如果之前元素被访问且当前没有终止,那就是相等;如果之前被访问且当前新增有访问,那就是相加;如果之前被访问且当前终止了,那就是相减。只是这些对当前位置的新增询问和终止询问的操作都记录在count[i]上了,用前缀和count[i] += count[i-1],即是当前被访问次数。
之后对应位置相乘累加即可,中间注意求模和强制转型。
class Solution {
public:
int maxSumRangeQuery(vector<int>& nums, vector<vector<int>>& requests) {
sort(nums.begin(), nums.end(), greater());
int n = nums.size();
long long MOD = 1e9 + 7;
long long ans = 0;
vector<int> count(n+1, 0);
for(auto x : requests) {
count[x[0]]++;
count[x[1] + 1]--;
}
for(int i = 1; i < n; i++)
count[i] += count[i-1];
sort(count.begin(), count.end(), greater());
int i = 0, j = 0;
while(j < n) {
ans += (long long)nums[i]*count[j] % MOD;
i++;
j++;
ans %= MOD;
}
return ans;
}
};