1. 题目来源
2. 题目说明
3. 题目解析
方法一:枚举+TOP-K问题+排序+巧妙解法
首先应该想到能不能暴力…枚举所有的情况比较求得一个最大团队表现值,显然暴力枚举不可能。其复杂度达到 O ( 2 n ) O(2^n) O(2n),那么就得对枚举进行简化,仅枚举有效的可能情况。
首先我们团队表现值有两部分构成,速度和及效率最小值,这是两个变量不易处理,所以我们应该定下一个变量再去对另一个变量进行枚举求解,如果第一个变量达到局部最优解,并且第二个变量达到局部最优解的话那么这就是一个备选答案,采用的就是贪心的思想。
速度和不易枚举,但是可以快速计算。那么就去枚举效率的最小值,那么所能得到的枚举结果就是效率值大于等于效率的最小值且速度和最大的 K
个。这就相当于维护效率值在效率最小值之上的 工程师速度中的 TOP-K
问题,就用堆来解决,即用优先队列进行实现。
我们对效率值进行降序排序,再依次加入工程师,那么当前加入进来的工程师一定是效率值最低的一个。在对维护的工程师中取 TOP-K 求速度和乘最低值,就是当前最低值所对应的最大团队表现值。枚举出所有最低值可能对应的答案,选择最大的那个就是整体的最大团队表现值。
总计:
- 根据效率值降序排序
- 维护
TOP-K
的速度之和,乘以新的工程师的效率值,注意在此优先队列维护最大值,所以我们把速度取负值在放进优先队列中,这也是常规操作了。并维护队列中的速度和sum
- 若当前堆内元素大于
k
个,则在sum
中减去堆顶速度,再将堆顶pop
掉即可 - 每次用
sum
乘以新添加进来的工程师的效率值求最大即可
参见代码如下:
// 执行用时 :120 ms, 在所有 C++ 提交中击败了100.00%的用户
// 内存消耗 :17.8 MB, 在所有 C++ 提交中击败了100.00%的用户
const int MAXN = 1e5 + 50;
struct Engineer{
long long s, e;
}p[MAXN];
const long long MOD = 1e9 + 7;
inline bool cmp(const Engineer &a, const Engineer &b){ return a.e > b.e; }
priority_queue<long long> que;
class Solution {
public:
int maxPerformance(int n, vector<int>& speed, vector<int>& efficiency, int k) {
for (int i = 0; i < n; i++){
p[i].s = speed[i];
p[i].e = efficiency[i];
}
sort(p, p + n, cmp);
while(!que.empty()) que.pop();
long long sum = 0;
long long ans = 0;
for (int i = 0; i < n; i++){
sum += p[i].s;
que.push(-p[i].s);
while(que.size() > k){
sum += que.top(); que.pop();
}
ans = max(ans, sum * p[i].e);
}
return ans % MOD;
}
};
在此对于 sort()
对 vector
数组排降序,之前的操作的话要么正常调用再进行 reverse
,要么就是写 lambda
表达式,要么就写个 cmp
函数就行了,上面就是这个写法。
大佬 Ikaruga 题解 给出了反向迭代器排降序的方法,充满了香气 ~ tql ~
下面贴下大佬的代码:
int maxPerformance(int n, vector<int>& speed, vector<int>& efficiency, int k)
{
const int mod = 1000000007;
vector<vector<int>> es;
for (int i = 0; i < efficiency.size(); i++)
{
es.push_back({ efficiency[i], speed[i] });
}
sort(es.rbegin(), es.rend());
long long ans = 0;
long long sum = 0;
long long eff = INT_MAX;
priority_queue<int, vector<int>, greater<int>> que;
for (int i = 0; i < es.size(); i++)
{
eff = es[i][0];
sum += es[i][1];
que.push(es[i][1]);
if (--k < 0)
{
sum -= que.top();
que.pop();
}
ans = max(ans, sum * eff);
}
return ans % mod;
}
4. 本周赛总结
话说本周赛没啥好总结的,自己报名了,忘记周天了,就忘记参加了,成守门员了。
不过针对题目来讲,是这几周最为简单的题目了,没有那么多图、难度 dp
,深广搜问题。即便是最后一题也只能与一般的 dp
相提并论。做的时候前三题还是很快解决,一遍 AC
,最后一道心生畏惧,读了好长时间题目,恰有群大佬讨论看了思路才勉强搞定,所以,菜是原罪~