【每日一题】3月25日tokitsukaze and Soldier
tokitsukaze and Soldier
https://ac.nowcoder.com/acm/problem/50439
题目意思
给定n个人,每个人有武力值和忍耐人数上线,需要最终组成一个团去计算最终的最大武力值之和。
解题思路
很容易想到,枚举每个人的s值,求解在这个s值下选取适当的人的最大武力值是多少,最终的最大答案就是题目要求得答案。
上面是一种思路,但是极其难实现,想想为啥,每个人的s值不同,选定一个人的s值,再选s-1个人中,可能改变最小的s值。。。
我们又找到s大的与s小的对比,我们要注意得是s小的人,因为如果选定了这个人是在答案中,先达到饱和的一定是s小的。
那么我们想对s进行一次降序排序,从大到小枚举s。那么我们又如何去按照这个s值求解答案呢?
我们知道如果选定了一个k,表示团队最大人数。那么我们就可以在s[i]大于等于k中选取武力值最大的k个人。
k根据题目可以取到每个人的s值。
那么要如何记录满足当前人s得情况下,得武力值最大呢,没错选择小根堆(优先队列),我们把武力值小的人放在堆顶。
每次如果当前堆中元素大于了这个人的s,那么我们就把堆顶元素删除,对应武力值之和去掉堆顶元素。
最后对每个人的s值求解一遍,最终留下最符合要去的最大的就是答案。
Code
#include <bits/stdc++.h> using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) typedef long long ll; inline int read() { int s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); } while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return s * w; } const int N = 1e5 + 7; struct Node { ll w; int s; bool operator<(const Node& a)const { return s > a.s; } }a[N]; priority_queue<ll, vector<ll>, greater<ll> > pq; // 小根堆,如果不加vector只后内容默认为大根堆,大值在堆顶,注意> >有空格 int main() { int n = read(); for (int i = 1; i <= n; ++i) a[i].w = read(), a[i].s = read(); //按照s的降序排序 sort(a + 1, a + 1 + n); // tmp是当前这个人的s前提下最大,ans是最终答案 ll ans = 0, tmp = 0; for (int i = 1; i <= n; ++i) { tmp += a[i].w; pq.push(a[i].w); // 满足当前这个人的s情况下,最大 // 也就是k从大到小的取值,取遍所有k,求得最大答案 while (pq.size() > a[i].s) { tmp -= pq.top(); pq.pop(); } //更新答案 ans = max(ans, tmp); } printf("%lld\n", ans); return 0; }
每日一题 文章被收录于专栏
每日一题