PIPI打怪题解——转换+贪心

题目描述:

xx被恶魔攻占了!

里面有数不清的敌人,PIPI拿着一把附魔枪,射出的子弹会在敌人间跳跃,一发子弹就能对所有敌人造成 2 点伤害,如果该子弹导致了任意敌人死亡(即血量小于等于 0),该子弹还会再次对所有敌人造成2点伤害,直到没有新的敌人死亡为止。

那么,PIPI需要打出几颗子弹才能消灭所有敌人呢?

输入:

输入包含多组测试用例。

第一行包含一个数字n,代表敌人数量。

第二行n个数,代表每个敌人的血量,用空格分开,回车结束。

0<n<=10000; 0<敌人的血量<=10^9

输出:

对于每组输入,输出是一个数字,代表PIPI最少需要打出的子弹的个数。

样例输入:

5

1 12 3 6 10

样例输出:

2

思路:

最容易想到的是暴力解法:不断遍历,有敌人的血量小于等于0就再次做此次操作,知道所有敌人血量全空为止。此解法在数据10^4下大概率会超时,我们不妨换种思路,对每个血量转换成所需的子弹数,例如7——4, 10——5......

再来找子弹能连续的条件,如果一个敌人A需要3颗子弹,而另一个B需要4颗,很显然,当A血量空了之后,此时B还需一颗子弹,而A血量空触发连续机制,故下一颗子弹能连续把B的血量击空,而如果当B需要5颗,当A血量空之后,此时触发连续机制,最后B还需1颗才能击杀,此时A与B不会连续被击杀。

总结:当一个敌人所需的子弹数比上一个死亡的敌人所需的子弹数不大于1,则不用另加子弹,反之需要加子弹,当然血量越少的敌人越先空血,我们需要将数组从小到大排序,这样,如果需要另加子弹,a[i]-a[i-1]+1即为所需另加的子弹数,总的子弹数即为两部分:击杀最少血量所需的子弹数+除最少的外,其他相差>1的情况所需的子弹数。

例如对样例转换排序后:1 2 3 5 6

第一部分只需一颗子弹,而1 2 3 相差<=1,此时不需另加子弹,而3 5直接相差>1,需另加5-3-1=1颗子弹,而5 6同理不需另加子弹,总子弹数为1+1=2

ac代码如下:

时间复杂度为nlogn

#include<bits/stdc++.h>
using namespace std;
int trans(int a)         //对每个血量转换成其所需的子弹数
{
    if(a%2==0) return a/2;
    else
    {
        return a/2+1;
    }
}
int n;
int a[10005];
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
    for(int i=1;i<=n;i++)
    {
        int b;
        scanf("%d",&b);
        a[i]=trans(b);
    }
    sort(a+1,a+1+n);         //调用sort函数,对所需子弹数进行升序排序
    int ans=0;
    ans+=a[1];               //第一部分,即打死最少血量敌人所需的子弹数
    for(int i=1;i<=n;i++)
    {
        if(i==1||a[i]-a[i-1]==0||a[i]-a[i-1]==1) continue;        //如果当前敌人所需子弹数比 
        上一敌人所需子弹数不大于1,子弹即可连续
        else ans+=a[i]-a[i-1]-1;             //如果数组间断,则需另加子弹
    }
    printf("%d\n",ans);
    }
     return 0;
}

原题出处:CSUOJ

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值