CSP-S2024提高级T1:决斗

题目链接

CSP-S2024提高级T1:决斗

题目描述

今天是小 Q 的生日,他得到了 n n n 张卡牌作为礼物。这些卡牌属于火爆的“决斗怪兽”,其中,第 i i i 张卡代表一只攻击力为 r i r_i ri,防御力也为 r i r_i ri 的怪兽。

一场游戏分为若干回合。每回合,小 Q 会选择某只怪兽 i i i 以及另一只怪兽 j ( i ≠ j ) j(i \neq j) j(i=j),并让怪兽 i i i 向怪兽 j j j 发起攻击。此时,若怪兽 i i i 的攻击力小于等于怪兽 j j j 的防御力,则无事发生;否则,怪兽 j j j 的防御被打破,怪兽 j j j 退出游戏不再参与到剩下的游戏中。一只怪兽在整场游戏中至多只能发起一次攻击。当未退出游戏的怪兽都已发起过攻击时,游戏结束。

小 Q 希望决定一组攻击顺序,使得在游戏结束时,未退出游戏的怪兽数量尽可能少。

输入格式

输入的第一行包含一个正整数 n n n,表示卡牌的个数。

输入的第二行包含 n n n 个正整数,其中第 i i i 个正整数表示第 i i i 个怪兽的攻击力及防御力 r i r_i ri

输出格式

输出一行包含一个整数表示游戏结束时未退出游戏的怪兽数量的最小值。

样例 #1

样例输入 #1

5
1 2 3 1 2

样例输出 #1

2

样例 #2

样例输入 #2

10
136 136 136 2417 136 136 2417 136 136 136

样例输出 #2

8

提示

【样例 1 解释】

其中一种最优方案为:第一回合让第 2 2 2 只怪兽向第 1 1 1 只怪兽发起攻击,第二回合让第 5 5 5 只怪兽向第 4 4 4 只怪兽发起攻击,第三回合让第 3 3 3 只怪兽向第 5 5 5 只怪兽发起攻击。此时没有退出游戏的怪兽都进行过攻击,游戏结束。可以证明没有更优的攻击顺序。

【数据范围】

对于所有测试数据,保证: 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1n105 1 ≤ r i ≤ 1 0 5 1 \leq r_i \leq 10^5 1ri105

测试点 n n n r i r_i ri特殊性质
1 ∼ 4 1\sim 4 14 ≤ 10 \leq 10 10 ≤ 1 0 5 \leq 10^5 105无特殊性质
5 ∼ 10 5\sim 10 510 ≤ 1 0 5 \leq 10^5 105 ≤ 2 \leq 2 2无特殊性质
11 ∼ 15 11\sim 15 1115 ≤ 30 \leq 30 30 ≤ 1 0 5 \leq 10^5 105特殊性质 A
16 ∼ 20 16\sim 20 1620 ≤ 1 0 5 \leq 10^5 105 ≤ 1 0 5 \leq 10^5 105无特殊性质

特殊性质 A:保证每个 r i r_i ri 在可能的值域中独立均匀随机生成。

算法思想

根据题目描述,若怪兽 i i i 的攻击力大于怪兽 j j j 的防御力,怪兽 j j j 的防御被打破,然后退出游戏,求游戏结束时,最少留下几个的怪兽?

为了能够让退出游戏的怪兽尽可能多,要用攻击力高的怪兽去攻击防御力小的,那么可以将怪兽按照攻击力/防御力从小到大排序,如下图所示:
在这里插入图片描述
然后按照攻击力从小到大遍历,对于第 i i i只怪兽,遍历 1 ∼ i − 1 1\sim i-1 1i1的每只怪兽 j j j

  • 如果它还没有退出游戏,则退出游戏的怪兽数增加1。

最后用怪兽总数 n − n- n退出游戏的怪兽数,得到答案。

这样做的话时间复杂度为 O ( n 2 ) O(n^2) O(n2),可以拿到50分。

算法优化

由于题目中攻击力/防御力为 [ 1 , 1 0 5 ] [1,10^5] [1,105]的正整数,可以使用计数排序的思想,统计每个攻击力的怪兽数量,然后从小到大遍历攻击力 i i i,不妨设攻击力为 i i i的怪兽个数为 c n t [ i ] cnt[i] cnt[i],防御力小于 i i i的怪兽个数为 s u m sum sum

  • 如果 s u m ≤ c n t [ i ] sum\le cnt[i] sumcnt[i],那么防御力小于 i i i的怪兽全部退出游戏, s u m = 0 sum=0 sum=0
  • 否则,会有 c n t [ i ] cnt[i] cnt[i]个怪兽退出游戏, s u m − = c n t [ i ] sum-=cnt[i] sum=cnt[i]
  • 最后,再将攻击力为 i i i怪兽累加到剩余怪兽中, s u m + = c n t [ i ] sum+=cnt[i] sum+=cnt[i]

这样, s u m sum sum就是游戏结束时最少留下的怪兽个数。

计数排序的时间复杂度为 O ( r i ) O(r_i) O(ri),这里 1 ≤ r i ≤ 1 0 5 1 \leq r_i \leq 10^5 1ri105,是满足要求的。

代码实现

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int cnt[N]; //cnt[i]表示防御力为i的怪兽的个数 

int main()
{
    int n, r, L = N, R = 0;
    cin >> n;
    for(int i = 1; i <= n; i ++)
    {
        cin >> r;
        cnt[r] ++;
        L = min(L, r);
        R = max(R, r);
    }
    int sum = cnt[L]; //统计未退出游戏的怪兽数量
    for(int i = L + 1; i <= R; i ++)
    {
        if(cnt[i] == 0) continue; //没有攻击力为i的怪兽
        if(sum <= cnt[i]) sum = 0; //如果防御力小于i的怪兽数量不超过攻击力为i的怪兽数量,那么全部退出
        else sum -= cnt[i]; //否则,剩余的怪兽数量减少cnt[i]个
        sum += cnt[i]; //将攻击力为i的怪兽累加到答案中
    }
    cout << sum << endl;
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少儿编程乔老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值