news 2026/6/10 22:08:19

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
信息学奥赛刷题实战: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方案——它可能不是绝对最快的,但绝对是代码最干净、最不容易出错的。特别是在时间紧迫的比赛环境中,减少调试时间往往比微小的性能提升更重要。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 21:59:17

Project Professional安装翻车实录:从MSI升级到即点即用的完整避坑指南

Project Professional安装升级全攻略&#xff1a;MSI与即点即用版本冲突解决方案 当企业用户或项目管理专业人士需要升级Project Professional时&#xff0c;常常会遇到新旧版本安装方式不兼容的问题。特别是从传统的MSI安装方式过渡到现代的即点即用版本时&#xff0c;系统往…

作者头像 李华
网站建设 2026/6/10 21:59:16

大模型落地关键:从ChatGPT界面迁移到业务系统内嵌AI

1. 项目概述&#xff1a;这不是一句口号&#xff0c;而是一次认知重启“Forget About ChatGPT”——看到这个标题&#xff0c;你第一反应可能是&#xff1a;这人是不是在蹭热点&#xff1f;或者干脆是反AI的保守派&#xff1f;其实都不是。我在过去三年里带过27个企业级AI落地项…

作者头像 李华
网站建设 2026/6/10 21:55:41

从OpenJudge一道题出发,聊聊C++里处理字符串输入的那些“坑”与技巧

从OpenJudge一道题出发&#xff0c;聊聊C里处理字符串输入的那些“坑”与技巧在C编程中&#xff0c;字符串输入看似简单&#xff0c;实则暗藏玄机。尤其是面对竞赛题目或实际项目中的复杂输入场景时&#xff0c;不少开发者都会在字符串处理上栽跟头。本文将以OpenJudge的一道典…

作者头像 李华