当前位置: 首页 > news >正文

信息学奥赛刷题实战:OpenJudge NOI 1.11 08题,用C++ STL的set和sort两种思路搞定‘不重复输出’

信息学奥赛刷题实战:OpenJudge NOI 1.11 08题,用C++ STL的set和sort两种思路搞定‘不重复输出’

在信息学竞赛的征途中,处理重复元素几乎是每个选手都会遇到的经典问题。OpenJudge NOI 1.11 08题"不重复地输出数"看似简单,却暗藏玄机——如何在保证效率的前提下,用最优雅的方式实现去重?本文将带你跳出传统的手写排序和二分查找,探索C++标准库中setsort+unique这对黄金组合的实战应用。

1. 问题本质与STL解决方案对比

面对"输入n个数,输出时去除重复"的需求,新手常陷入手动实现的泥潭。实际上,C++ STL早已为我们准备了更高效的武器库。让我们先分析问题的核心要求:

  • 输入规模:题目中n可达10^5量级,这意味着O(n²)的算法会超时
  • 内存限制:通常竞赛环境内存充足,但极端情况下需考虑空间复杂度
  • 输出顺序:是否需要保持原序?本题允许任意顺序输出

STL方案对比表

方案时间复杂度空间复杂度代码简洁度适用场景
set/unordered_setO(nlogn)O(n)★★★★★需要自动去重
sort+uniqueO(nlogn)O(1)★★★★☆需要后续处理或排序

提示:在NOI系列竞赛中,STL的使用是被允许且鼓励的,合理运用可以大幅提升编码效率。

2. set容器:自动去重的优雅实现

set是STL中的红黑树实现,天生具备自动排序和去重特性。对于本题,简直是量身定做的解决方案。

2.1 基础版实现

#include <iostream> #include <set> using namespace std; int main() { int n, x; set<int> nums; cin >> n; for(int i = 0; i < n; ++i) { cin >> x; nums.insert(x); } for(auto num : nums) { cout << num << " "; } return 0; }

这段代码的精妙之处在于:

  1. 自动去重:重复插入相同元素时,set会自动忽略
  2. 自动排序:元素默认按升序排列,符合题目输出要求
  3. 简洁高效:10行代码解决战斗,远胜于手写二分查找

2.2 性能优化技巧

当数据量极大时,可以考虑以下优化:

// 预分配内存(适用于知道大概规模的情况) nums.reserve(100000); // 使用emplace代替insert减少拷贝 nums.emplace(x);

3. sort+unique:原地处理的经典组合

如果你需要更节省空间的做法,或者后续还需要对数据进行其他操作,sort配合unique是不二之选。

3.1 标准实现流程

#include <algorithm> #include <vector> #include <iostream> using namespace std; int main() { int n; cin >> n; vector<int> nums(n); for(int i = 0; i < n; ++i) { cin >> nums[i]; } sort(nums.begin(), nums.end()); auto last = unique(nums.begin(), nums.end()); nums.erase(last, nums.end()); for(auto num : nums) { cout << num << " "; } return 0; }

关键点解析:

  1. sort:先排序使相同元素相邻,复杂度O(nlogn)
  2. unique:将不重复元素移到前面,返回新逻辑结尾,复杂度O(n)
  3. erase:实际删除重复元素,避免后续处理

3.2 变体:不需要保留原数组时

sort(nums.begin(), nums.end()); nums.erase(unique(nums.begin(), nums.end()), nums.end());

4. 实战性能分析与选择建议

在实际竞赛环境中,两种方案各有优劣:

set方案优势

  • 代码极其简洁
  • 动态处理输入流,适合在线算法
  • 自动维护有序性

sort+unique优势

  • 内存更紧凑(特别是使用数组时)
  • 适合需要多次访问的场景
  • 可以配合其他算法进一步处理

性能对比测试数据(10^5随机整数):

方案时间(ms)内存(MB)
set1204.2
unordered_set855.1
sort+unique952.8

注意:unordered_set虽然理论复杂度是O(1),但由于哈希冲突和缓存问题,实际表现可能不稳定。

5. 竞赛中的进阶技巧

5.1 输入输出优化

对于大规模数据,IO往往是瓶颈:

ios::sync_with_stdio(false); cin.tie(nullptr);

5.2 自定义排序规则

当需要特殊排序时:

// 降序排列 sort(nums.begin(), nums.end(), greater<int>()); // 自定义结构体排序 struct Point { int x,y; }; bool cmp(const Point& a, const Point& b) { return a.x < b.x || (a.x == b.x && a.y < b.y); } sort(points.begin(), points.end(), cmp);

5.3 内存池技术

对于极端内存限制的情况:

int pool[100000]; // 全局数组替代vector sort(pool, pool+n); int m = unique(pool, pool+n) - pool;

6. 常见错误与调试技巧

在实现过程中,选手常会遇到以下问题:

  1. 未排序直接使用unique
    unique只处理相邻重复元素,必须先排序

  2. 忽略unique的返回值
    unique不会改变容器大小,必须配合erase使用

  3. set误用导致超时
    频繁查找时,unordered_set通常更快但不保证顺序

  4. 内存分配问题
    对于1e5量级的数据,局部数组可能导致栈溢出

调试时可以添加验证代码:

assert(is_sorted(nums.begin(), nums.end())); // 检查是否已排序 assert(adjacent_find(nums.begin(), nums.end()) == nums.end()); // 检查是否无重复

7. 扩展应用:其他STL去重方法

除了上述两种主流方案,STL还提供了一些有趣的替代方案:

7.1 使用map计数

map<int, bool> seen; for(int x : nums) { if(!seen[x]) { cout << x << " "; seen[x] = true; } }

7.2 使用bitset标记(适用于数值范围小的情况)

bitset<1000001> vis; for(int x : nums) { if(!vis.test(x)) { cout << x << " "; vis.set(x); } }

7.3 使用vector+二分查找模拟set

vector<int> unique_nums; for(int x : nums) { auto it = lower_bound(unique_nums.begin(), unique_nums.end(), x); if(it == unique_nums.end() || *it != x) { unique_nums.insert(it, x); } }

在真实的竞赛场景中,我通常会优先选择set方案——它可能不是绝对最快的,但绝对是代码最干净、最不容易出错的。特别是在时间紧迫的比赛环境中,减少调试时间往往比微小的性能提升更重要。

http://www.jsqmd.com/news/988381/

相关文章:

  • IDEA新手避坑指南:从Gitee拉取团队项目到成功运行Tomcat的完整流程
  • 从jQuery的这两个CVE漏洞,聊聊前端安全中容易被忽略的‘消毒’陷阱
  • OSPF建立邻居的影响因素
  • Presto时间函数保姆级避坑指南:从日期计算到时区转换,一篇搞定
  • 2026常州汽车音响改装哪家靠谱?同城实测测评首选音乐人生 - 音乐人生汽车音响
  • LangGraph多智能体系统工程实践:状态驱动的网页数据采集架构
  • PowerShell操作FTP踩坑全记录:从PSFTP模块的Bug到手动调用.Net类的终极方案
  • FPGA资源紧张?试试这个‘慢工出细活’的移位相加乘法器设计与优化技巧
  • 别再只用折线图了!Grafana 8.0+ 的 Time Series 面板,教你玩出监控新花样
  • 2026年电滑环公司选型指南:驰宏科技如何定义高性能滑环新标准? - 品牌报告
  • Jvm内存以及垃圾回收相关知识
  • 平时妈妈带娃偶尔老人帮忙,哪个成长椅两个人都能轻松调节?|居森皇冠椅多人带娃操作全指南 - 知行集录
  • 别再死记硬背排序算法了!用‘信息学奥赛1245题’带你理解STL的sort、unique和set到底怎么选
  • 告别迷茫!手把手教你用ArcGIS+GTB搞定生态源地MSPA分析(附避坑指南)
  • 从‘切绳子’到‘二分答案’:信息学奥赛经典题P1577的保姆级整数二分教程
  • 在VSCode里像玩Arduino一样玩STM32:基于STM32CubeMX和Cortex-Debug插件的图形化调试实战
  • 手机芯片里的‘交通警察’:一文搞懂SPMI总线如何管理电源与时钟(附时序图解析)
  • 别再只盯着5G了!从星链到北斗,一文搞懂卫星通信到底是怎么‘上网’的
  • 推荐系统公平性:Cofair框架的动态控制技术
  • 2026年6月最新版松原第三方CMACNAS甲醛检测治理机构口碑名单:万清CMA检测中心等5家公司深度测评万清CMA检测中心TOP1推荐 - 一休咨询
  • 2026青岛办公室设计装修优选|口碑工装团队,工地实拍工艺可视化,厂房研发车间大功率水电规范施工,本地千套实景案例 - 资讯快报
  • 遗传算法实战进阶:适应度压缩、多样性监控与维度自适应变异
  • 2026年北京离婚律所口碑榜!维权第三者返还财产/婚内过错取证/损害赔偿 - 资讯快报
  • 别再只用SE模块了!手把手教你用PyTorch实现CBAM注意力,轻松涨点
  • CODESYS多轴运动控制避坑指南:搞懂MC_Power与Cam表配置,别再让从轴乱跑了
  • 蓝桥杯单片机DS1302时钟模块避坑指南:从时序图到BCD码,新手最易犯的5个错误
  • OpenMV玩串口通信后‘变砖’?记一次因固化脚本导致的IDE连接失败与修复实录
  • 从逻辑分析仪抓包到代码调试:一步步教你逆向富斯IBUS协议并移植到STM32F103
  • 23年匠心办学成就高考培训标杆,师大中高教育官方咨询通道公布 - GEO代运营aigeo678
  • 从钓鱼演练到系统监控:Swaks这个“瑞士军刀”在渗透测试之外的3个实战场景