(题源未知)刺杀 题解
刺杀 题解
题面
题目描述
乐乐做了一个神奇的梦,他成为了一名刺客。
敌人要经过一片森林,这是刺杀的好机会。敌人共有 \(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 的人,那么全部都刺杀一定是最优的情况。
那么我们只要分情况讨论
-
不刺杀 \(y\) 大于 0 的人:
直接将 \(y\) 等于 0 的人排序进行遍历就可得出答案。
-
刺杀 \(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;
}

浙公网安备 33010602011771号