(题源未知)刺杀 题解

刺杀 题解


题面

题目描述

乐乐做了一个神奇的梦,他成为了一名刺客。

敌人要经过一片森林,这是刺杀的好机会。敌人共有 \(n\) 个,每个人有一个体力值 \(x\) 和子弹数 \(y\),表示如果乐乐徒手打败这个人需要消耗 \(x\) 点体力,打败这个人之后,他就会得到一把含有 \(y\) 颗子弹的手枪(这把手枪可以杀死 \(y\) 个人)。

乐乐刚开始只有 \(s\) 点体力,并且没有手枪(体力消耗后不会恢复,体力不能小于 0)。

乐乐刺杀一名敌人,有两种方法:通过体力肉搏或者通过开枪射击。

请你帮乐乐算算,他最多可以刺杀多少敌人和刺杀这些敌人需要消耗的最少体力数。

输入格式

第一行两个整数,\(n\)\(s\),表示敌人的数量和乐乐最初的体力值。

接下来 \(n\) 行,每行两个整数 \(x\)\(y\)

输出格式

输出两个整数,表示最多的敌人数以及最少的体力消耗。

样例

输入

3 5
4 1
5 1
7 7
2 1
2 2
4 0

输出

3 4
0 0

数据范围与提示

对于 \(30\%\) 的数据,\(n \in [1,10]\)

对于 \(50\%\) 的数据,\(n \in [1,100]\)

对于 \(70\%\) 的数据,\(n \in [1,1000]\),其中有 \(5\%\) 的数据,\(y = 0\)

对于 \(100\%\) 的数据,\(n \in [1,10^5],x,s\in[0,10^9],y \in [0,10]\)


题意分析

略略略。


思路分析

我们发现可以根据每个人的 \(y\) 是否大于 0 来分组。

如果要刺杀 \(y\) 大于 0 的人,那么全部都刺杀一定是最优的情况。

那么我们只要分情况讨论

  1. 不刺杀 \(y\) 大于 0 的人:

    直接将 \(y\) 等于 0 的人排序进行遍历就可得出答案。

  2. 刺杀 \(y\) 大于 0 的人:

    先将 \(y\) 大于 0 的人与 \(y\) 等于 0 的人分别排序,刺杀 \(y\) 大于 0 的人中 \(x\) 最小的人,然后不停地取两个集合中最小的人刺杀,直至子弹的总量可以刺杀余下的所有人。不过有个特判:可能没有 \(y\) 大于 0 的人、\(y\) 大于 0 的人一个都杀不掉。


CODE

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define max(a,b) ((a)<(b)?(b):(a))
#define min(a,b) ((a)>(b)?(b):(a))
#define tomax(a,b) ((a)=max((a),(b)))
#define tomin(a,b) ((a)=min((a),(b)))
#define RCL(a,b,c,d) memset((a),(b),sizeof(c)*(d))
#define FOR(i,a,b) for(register int i=(a);i<=(b);++i)
#define DOR(i,a,b) for(register int i=(a);i>=(b);--i)
#define EDGE(g,i,u,x) for(register int (i)=(g).h[(u)],(x)=(g).v[(i)];(i);(i)=(g).nxt[(i)],(x)=(g).v[(i)])
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0);return Main();}signed Main
using namespace std;
constexpr int N=1e5+10;
int n,S,s,sum,ans,cnt,ansN,ansS;
vector<int> vec[2],tmp;
signed main(){
	cin>>n>>s,S=s;
	FOR(i,1,n){
		int x,y;
		cin>>x>>y,sum+=y,vec[y>0].push_back(x);
	}
	sort(vec[0].begin(),vec[0].end(),greater<>()),sort(vec[1].begin(),vec[1].end(),greater<>());
	for(copy(vec[0].begin(),vec[0].end(),back_inserter(tmp));!tmp.empty()&&tmp.back()<=s;tmp.pop_back())
		++ans,s-=tmp.back();
	ansN=ans,ansS=S-s,tmp.clear(),s=S,ans=0;
	if(!vec[1].empty()){
		for(s-=vec[1].back(),vec[1].pop_back(),ans=1;!vec[0].empty()||!vec[1].empty();++ans){
			if(ans+sum>=n||s<min(vec[0].back(),vec[1].back()))break;
			if(vec[1].empty()||!vec[0].empty()&&vec[0].back()<vec[1].back())s-=vec[0].back(),vec[0].pop_back();
			else s-=vec[1].back(),vec[1].pop_back();
		}
		ans=min(n,ans+sum);
		if(ansN<ans)ansN=ans,ansS=S-s;
		else if(ansN==ans)tomin(ansS,S-s);
	}
	cout<<ansN<<" "<<ansS<<endl;
	return 0;
}

posted @ 2024-07-04 20:05  Add_Catalyst  阅读(11)  评论(0)    收藏  举报