当前位置: 代码迷 >> 综合 >> 牛客网 tokitsukaze and Soldier 问题
  详细解决方案

牛客网 tokitsukaze and Soldier 问题

热度:50   发布时间:2024-02-09 19:36:46.0

来源:牛客网

题目描述 
在一个游戏中,tokitsukaze需要在n个士兵中选出一些士兵组成一个团去打副本。
第i个士兵的战力为v[i],团的战力是团内所有士兵的战力之和。
但是这些士兵有特殊的要求:如果选了第i个士兵,这个士兵希望团的人数不超过s[i]。(如果不选第i个士兵,就没有这个限制。)
tokitsukaze想知道,团的战力最大为多少。
输入描述:
第一行包含一个正整数n(1≤n≤10^5)。
接下来n行,每行包括2个正整数v,s(1≤v≤10^9,1≤s≤n)。
输出描述:
输出一个正整数,表示团的最大战力。示例1
输入
2
1 2
2 2

这个题还是妙啊。好好想想该怎么做。循序渐进
首先,如果没有人数限制,或者说,限制k个人,那怎么选,肯定选战斗力最强的k个。限制可以枚举k,每次都选战斗力最强的k个。然后肯定复杂度比较高,看能不能复用。所以按每个士兵允许的人数,进行排序。从大到小。先把最多容纳的人拉进来,然后再多放一个人进来,维护总人数(用堆来表示),然后把战斗力最弱的弹出,实时记录最小值。
不行自己写了。
参考代码,c语言

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100020;
#define LL long long
priority_queue<LL, vector<LL>, greater<LL> > q;
//形如“priority_queue<LL> q”是大根堆,上一行写法是小根堆,注意两个>之间一定要有一个空格
struct ty
{LL v;int s;bool operator < (const ty &a) const{return s > a.s;}
}a[maxn];
int main()
{int n;scanf("%d", &n);for(int i = 1; i <= n; i++){scanf("%lld%d",&a[i].v, &a[i].s);}sort(a+1, a+n+1);//按照s从大到小排序,之后就根据这个数组来枚举队伍人数kLL tmp = 0, ans =0;//tmp用来存当前还在队伍里面的人的武力值之和,堆里的人就是还在队伍里的人for(int i = 1; i <= n; i++){tmp += a[i].v;q.push(a[i].v);//把当前这个s最大的还没加入堆的人加入堆while(q.size() > a[i].s){tmp -= q.top();q.pop();   //人数超出了就删除堆顶}//第i个人加入堆里之后,当前对人数的限制就是p[i].s(之前加入的人都比他的s值大)//这里就相当于题解说的从大到小枚举kans = max(ans, tmp);}printf("%lld", ans);return 0;
}

niubility!!!
好了。