当前位置: 首页 > 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.gsyq.cn/news/1500132.html

相关文章:

  • 从DZ47到智能空开:手把手教你读懂断路器型号代码,选型不求人
  • IDEA新手避坑指南:从Gitee拉取团队项目到成功运行Tomcat的完整流程
  • 从jQuery的这两个CVE漏洞,聊聊前端安全中容易被忽略的‘消毒’陷阱
  • Presto时间函数保姆级避坑指南:从日期计算到时区转换,一篇搞定
  • 2026常州汽车音响改装哪家靠谱?同城实测测评首选音乐人生 - 音乐人生汽车音响
  • Jvm内存以及垃圾回收相关知识
  • 平时妈妈带娃偶尔老人帮忙,哪个成长椅两个人都能轻松调节?|居森皇冠椅多人带娃操作全指南 - 知行集录
  • 告别迷茫!手把手教你用ArcGIS+GTB搞定生态源地MSPA分析(附避坑指南)
  • 手机芯片里的‘交通警察’:一文搞懂SPMI总线如何管理电源与时钟(附时序图解析)
  • 别再只用SE模块了!手把手教你用PyTorch实现CBAM注意力,轻松涨点
  • OpenMV玩串口通信后‘变砖’?记一次因固化脚本导致的IDE连接失败与修复实录
  • 从逻辑分析仪抓包到代码调试:一步步教你逆向富斯IBUS协议并移植到STM32F103
  • MC13892电源管理芯片动态特性与引脚设计实战解析
  • 避坑指南:华为AC旁挂组网,Option 43配错导致AP不上线?手把手教你三层发现AC的正确姿势
  • 2026年广告创意公司/医药广告创意代理TOP5榜单:品牌策略与合规传播的破局之道 - 品牌发掘
  • 告别卡顿!从RRC重配置流程看手游/直播为何突然流畅——5G QoS的幕后功臣DRB建立详解
  • Altium Designer 19 自定义库管理实战:解决‘画了找不到’和工具栏消失问题
  • 2026年6月最新版苏州第三方CMACNAS甲醛检测治理机构口碑名单:万清CMA检测中心等5家公司深度测评万清CMA检测中心TOP1推荐 - 一休咨询
  • CloudCompare点云高程归一化保姆级教程:从CSF到泊松重建,四种方法实测对比与避坑指南
  • Python 爬虫项目 Cookie 池搭建与会话隔离实战
  • mysql应用层分表(Application-Level Sharding)知识笔记
  • 多维聚合实战:ROLLUP、CUBE与GROUPING SETS原理与优化
  • 多维聚合中的数据操纵:从OLAP立方体到CEO驾驶舱的四层解剖
  • 从OpenJudge一道题出发,聊聊C++里处理字符串输入的那些“坑”与技巧
  • 不止是列表:用RimWorld的Def系统设计你的第一个原创事件(IncidentDef实战)
  • 告别AP直连:用华为AC+交换机搭建可扩展的无线办公网(隧道转发详解)
  • ggplot2分面进阶:用ggh4x包的facetted_pos_scales函数优雅定制每个面板的坐标轴
  • 别再只会用插值了!用PyTorch的PixelShuffle层实现更自然的图像超分辨率
  • 上海企业搬迁公司推荐:主流厂商对比参考 - 资讯快报
  • 2026年6月伺服冲床企业选哪家,25吨伺服模切冲床/片材伺服模切冲床/小吨位伺服冲床,伺服冲床厂家哪家权威 - 品牌推荐师