刺杀

题目描述 乐乐做了一个神奇的梦,他成为了一名刺客。
敌人要经过一片森林,这是刺杀的好机会。敌人共有n个,每个人有一个体力值x和子弹数y,表示如果乐乐徒手打败这个人需要消耗x点体力,打败这个人之后,他就会得到一把含有y颗子弹的手枪(这把手枪可以杀死y个人)。
乐乐刚开始只有s点体力,并且没有手枪(体力消耗后不会恢复,体力不能小于0)。 乐乐刺杀一名敌人,有两种方法:通过体力肉搏或者通过开枪射击。
请你帮乐乐算算,他最多可以刺杀多少敌人和刺杀这些敌人需要消耗的最少体力数。 输入 第一行两个整数,n和s,表示敌人的数量和乐乐最初的体力值。 接下来n行,每行两个整数x和y。
输出 输出两个整数,表示最多的敌人数以及最少的体力消耗
对于30%的数据,n的范围[1,10]; 对于50%的数据,n的范围[1,100];
对于70%的数据,n的范围[1,1000],其中有10%的数据,y的值为0;
对于100%的数据,n的范围[1,10^5],x、s的范围[0,10^9],y的范围[0,10];

刚开始看这到题目感觉是dp,但显然dp的复杂度根本过不了这道题

首先我们可以知道体力是不会恢复的,所以我们可以选择任意顺序去跟人肉搏
即你可以先跟消耗体力值大的打,也可以跟消耗体力值小的人打(只要体力不会降为零)

进一步可以得出,我们若把身上有子弹的人分成一组,那么只要我们把其中体力值最小的人肉搏死,那么这一组的人都可被枪毙。

或许在这里我们会想到把剩下的人体力值大的枪毙,再贪心肉搏体力值小的
表面看起来没有什么问题,但万一有枪的人的x比剩下人的x小,我们肯定要优先肉搏有枪的那个人,然后把子弹留下来枪毙x大的那个人

还有一点需要注意的是,后来枪毙的人不一定一定要被枪毙,可能我们还要把他弹出来肉搏
所以这一动态过程完全可以通过优先队列实现

同时有几个要特判的小点:
1.子弹过多(所有人都可被枪毙)
2.没有子弹
3.直接肉搏可能更好(因为如果要获得子弹,那一定要肉搏有子弹中x最小的那个,但可能x特别大,还不如直接肉搏没子弹的)

#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define M 100005
int A[M];//被gang死的人
int ans,ans1,HP1,cnt,cnt1,HP;
priority_queue<int,vector<int>,greater<int> >q;
int main() {
    int n,res=0;//res记录子弹数
    scanf("%d%d",&n,&HP);
    int tta=HP;HP1=HP;
    FOR(i,1,n) {
        int x,y;
        scanf("%d%d",&x,&y);
        if(y){q.push(x);res+=y;cnt1++;}
        else A[++cnt]=x;
    }
    sort(A+1,A+cnt+1);
    FOR(i,1,cnt){
        if(HP1>=A[i]){
            HP1-=A[i];
            ans1++;
        } 
        else break;
    }
    if(!q.empty())HP-=q.top();q.pop();
    if(HP<0||res==0){printf("%d %d\n",ans1,tta-HP1);return 0;}
    res=res-cnt1+1;//剩余子弹数 
    if(res>=cnt||HP<0) {printf("%d %d\n",n,tta-HP);return 0;}
    ans=res+cnt1;//现在人数(死亡) 
    FOR(i,cnt-res+1,cnt)q.push(A[i]);
    FOR(i,1,cnt-res+1){
        if(q.top()<A[i]&&q.top()<=HP){
            ans++;
            HP-=q.top();
            q.pop();
            q.push(A[i]);
        }
        else if(HP>=A[i]){
            ans++;
            HP-=A[i];
        }
    }
    if(ans<ans1)printf("%d %d\n",ans1,tta-HP1);
    else printf("%d %d\n",ans,tta-HP);
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hitters数据集是一个关于棒球击球手的数据集,包含了19个变量。这些变量的含义如下: 1. 季节(Season):指示球员打击的年份季节,取值为1986或1987。 2. 球龄(Years):表示球员在大联盟的经验年数。 3. 球员名字(Name):击球手的名字。 4. 球队(Team):球员所属的球队。 5. 赛区(League):球队所属的赛区,分为美联和国联。 6. 外野手守位(Division):球员守备的外野位置,包括中外野手(CF)、右外野手(RF)和左外野手(LF)。 7. 打击总数(At-bats):球员在一个赛季内的打击次数。 8. 安打数(Hits):球员在一个赛季内累计的安打数。 9. 全垒打数(Home-runs):球员在一个赛季内击出的全垒打的数量。 10. 打点(Runs_batted_in):球员在一个赛季内累计的打点(即使其他跑者得分)。 11. 打席(Walks):球员在一个赛季内的打席数。 12. 投手被三振(Strike-outs):球员在一个赛季内被投手三振的次数。 13. 投打受死(Stolen-bases):球员在一个赛季内盗垒成功的次数。 14. 被刺杀(Caught-stealing):球员在一个赛季内被刺杀盗垒的次数。 15. 左权(Put-outs):球员在一个赛季内守备成功的标判次数。 16. 放手安守候(Assists):球员在一个赛季内助攻次数。 17. 错误(Errors):球员在一个赛季内犯的失误次数。 18. 蔬果年龄(Salary):球员在一个赛季内的工资水平。 19. 合同年限(League):球员合同的年限。 这些变量可以用来分析球员的打击能力、盗垒和守备表现以及与球队签订合同的相关因素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值