2024信奥赛C++提高组csp-s复赛真题及题解:决斗

题目描述
今天是小 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 ≤ 10 5 1 \leq n \leq 10^5 1≤n≤105, 1 ≤ r i ≤ 10 5 1 \leq r_i \leq 10^5 1≤ri≤105。
| 测试点 | n n n | r i r_i ri | 特殊性质 |
|---|---|---|---|
| 1 ∼ 4 1\sim 4 1∼4 | ≤ 10 \leq 10 ≤10 | ≤ 10 5 \leq 10^5 ≤105 | 无特殊性质 |
| 5 ∼ 10 5\sim 10 5∼10 | ≤ 10 5 \leq 10^5 ≤105 | ≤ 2 \leq 2 ≤2 | ^ |
| 11 ∼ 15 11\sim 15 11∼15 | ≤ 30 \leq 30 ≤30 | ≤ 10 5 \leq 10^5 ≤105 | 特殊性质 A |
| 16 ∼ 20 16\sim 20 16∼20 | ≤ 10 5 \leq 10^5 ≤105 | ^ | 无特殊性质 |
特殊性质 A:保证每个 r i r_i ri 在可能的值域中独立均匀随机生成。
思路分析
题目要求通过安排怪兽的攻击顺序,使得游戏结束时未退出游戏的怪兽数量尽可能少。经过分析,可以得出一个关键结论:最终存活的怪兽数量恰好等于所有攻击力中出现次数的最大值。这是因为在最优策略下,只有出现次数最多的那些攻击力的怪兽能够存活,其余攻击力的怪兽都可以被淘汰。
算法思路
- 统计每个攻击力值出现的次数。
- 找出出现次数的最大值。
- 该最大值即为最终存活怪兽的最小数量。
时间复杂度
- 读取输入和统计出现次数:O(n)
- 查找最大值:O(max( r i r_i ri)),其中 r i ≤ 10 5 r_i ≤ 10^5 ri≤105
- 总体复杂度为 O(n + max( r i r_i ri)),在给定数据范围内完全可行。
代码实现
cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXR = 100010; // r_i 的最大值
int cnt[MAXR];// 统计每个攻击力出现的次数,数组下标对应攻击力值
int main() {
int n; // 怪兽数量
cin >> n;
int maxCnt = 0; // 记录出现次数的最大值
for (int i = 0; i < n; i++) {
int r;
cin >> r;
cnt[r]++; // 攻击力为 r 的怪兽数量加1
maxCnt = max(maxCnt, cnt[r]); // 更新最大值
}
// 输出结果:最终存活怪兽的最小数量等于最大出现次数
cout << maxCnt << endl;
return 0;
}
功能分析
- 输入处理:读取怪兽数量 n 和每个怪兽的攻击力 r_i。
- 统计频率 :使用数组
cnt记录每个攻击力值出现的次数。 - 求最大值:在统计过程中实时更新出现次数的最大值。
- 输出结果:最大值即为最终存活怪兽的最小数量。
算法证明
- 贪心策略:从大到小处理攻击力值,每次尽可能用当前可用的攻击次数淘汰当前攻击力的怪兽。可用的攻击次数始终是历史出现次数的最大值。
- 最终存活数量等于最终可用的攻击次数,即所有攻击力中出现次数的最大值。
- 因此,直接输出最大出现次数即可得到最优解。
各种学习资料,助力大家一站式学习和提升!!!
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"########## 一站式掌握信奥赛知识! ##########";
cout<<"############# 冲刺信奥赛拿奖! #############";
cout<<"###### 课程购买后永久学习,不受限制! ######";
return 0;
}
1、csp信奥赛高频考点知识详解及案例实践:
CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转
CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转
信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html
2、csp信奥赛冲刺一等奖有效刷题题解:
CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新):https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
CSP信奥赛C++一等奖通关刷题题单及题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转
3、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html
4、CSP信奥赛C++竞赛拿奖视频课:
https://edu.csdn.net/course/detail/40437 点击跳转

· 文末祝福 ·
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"跟着王老师一起学习信奥赛C++";
cout<<" 成就更好的自己! ";
cout<<" csp信奥赛一等奖属于你! ";
return 0;
}