news 2026/9/11 21:29:12

C++信奥刷题:P5133 tb148字符串处理与扫描线算法解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++信奥刷题:P5133 tb148字符串处理与扫描线算法解析

1. 项目概述:信奥刷题与P5133 tb148题目解析

信奥刷题是信息学竞赛(OI)选手提升编程能力的必经之路。今天我们要拆解的是《信息学奥赛一本通》中的P5133 tb148题目——"tb148的客人"。这道题看似简单,却蕴含了字符串处理、逻辑判断等C++核心知识点,非常适合用来检验基础编码能力。

作为一道典型的信奥模拟题,它要求我们处理客人到达和离开的记录,最终统计特定时刻的在场人数。这类问题在实际编程竞赛中非常常见,比如ACM/ICPC、NOIP等赛事都经常出现类似的场景模拟题目。掌握这类题目的解法,不仅能提升比赛成绩,对日常开发中的日志分析、用户行为统计等场景也有直接帮助。

我选择用C++实现这道题目,因为C++作为信奥竞赛的官方指定语言,其高效的执行速度和丰富的STL库非常适合处理这类需要精确控制数据结构的问题。接下来,我将从题目分析、解题思路、完整实现到优化技巧,一步步带你吃透这道题。

2. 题目需求与核心算法分析

2.1 题目详细描述

题目描述:一家名为tb148的店铺会记录每位客人的到达和离开时间(保证所有时间点都不重复)。现在给定n条记录,每条记录格式为"in x"或"out x",分别表示客人在时刻x进入或离开店铺。最后询问m次,每次询问一个时间点y,要求输出此时店铺内的客人数量。

输入格式:

  • 第一行:整数n(1≤n≤1e5),表示记录条数
  • 接下来n行:每行"in x"或"out x"(1≤x≤1e9)
  • 第n+2行:整数m(1≤m≤1e5),表示询问次数
  • 接下来m行:每行一个整数y(1≤y≤1e9)

输出格式:

  • 对于每个询问y,输出一个整数表示y时刻店铺内的客人数量

2.2 算法选择与复杂度分析

这道题的核心在于高效处理时间点查询。最直观的暴力解法是:对于每个查询y,遍历所有记录,统计在y时刻之前进入且未离开的客人数量。但这种做法时间复杂度为O(m*n),当n和m都达到1e5时,总复杂度1e10显然无法通过。

更优的解法是:

  1. 将所有事件点(包括in、out和查询)按时间排序
  2. 使用扫描线算法,按时间顺序处理事件,维护当前在场人数
  3. 遇到in事件时人数+1,out事件时人数-1
  4. 遇到查询时记录当前人数

这种算法的时间复杂度主要来自排序的O((n+m)log(n+m)),后续处理是线性的O(n+m),完全能够处理题目给出的数据规模。

3. C++实现详解

3.1 数据结构设计

我们需要设计一个能够混合存储事件和查询的数据结构:

struct Event { int time; // 时间点 int type; // 0:in, 1:out, 2:query int index; // 对于查询,记录它是第几个查询 };

同时准备两个数组:

  • vector<Event> events存储所有事件和查询
  • vector<int> answers存储每个查询的答案

3.2 完整代码实现

#include <iostream> #include <vector> #include <algorithm> using namespace std; struct Event { int time; int type; // 0:in, 1:out, 2:query int index; // 仅对查询有效 }; bool compareEvents(const Event &a, const Event &b) { return a.time < b.time; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, m; cin >> n; vector<Event> events; // 读取n条记录 for (int i = 0; i < n; ++i) { string type; int x; cin >> type >> x; events.push_back({x, (type == "in" ? 0 : 1), -1}); } cin >> m; vector<int> answers(m); // 读取m个查询 for (int i = 0; i < m; ++i) { int y; cin >> y; events.push_back({y, 2, i}); } // 按时间排序所有事件 sort(events.begin(), events.end(), compareEvents); int current = 0; // 当前在场人数 // 处理所有事件 for (const auto &e : events) { if (e.type == 0) { // in事件 current++; } else if (e.type == 1) { // out事件 current--; } else { // 查询 answers[e.index] = current; } } // 输出所有查询结果 for (int ans : answers) { cout << ans << "\n"; } return 0; }

3.3 关键代码解析

  1. 输入处理部分

    • 使用ios::sync_with_stdio(false); cin.tie(nullptr);加速输入输出,这对处理大规模数据至关重要
    • 将in/out记录和查询统一存储为Event结构体,便于后续统一排序
  2. 排序部分

    • 自定义比较函数compareEvents,确保所有事件按时间升序排列
    • 使用STL的sort函数,时间复杂度O(N log N)
  3. 扫描线处理

    • 维护一个current变量表示当前在场人数
    • 按时间顺序处理每个事件,遇到in就+1,out就-1
    • 遇到查询时记录当前人数到answers数组
  4. 输出部分

    • 最后统一输出所有查询结果,避免频繁IO操作影响性能

4. 优化技巧与注意事项

4.1 性能优化要点

  1. 输入输出优化

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

    这两行代码可以显著提高C++的输入输出速度,特别是在处理大规模数据时。原理是禁用C++流与C流的同步,并解绑cin与cout的关联。

  2. 避免使用endl: 使用"\n"代替endl,因为endl会强制刷新输出缓冲区,导致性能下降。

  3. 预分配内存

    vector<Event> events; events.reserve(n + m); // 预分配足够空间

    对于已知大小的容器,预先reserve可以避免多次扩容带来的性能损耗。

4.2 常见错误与调试技巧

  1. 边界条件处理

    • 确保处理第一个事件前current初始化为0
    • 注意时间点相同的情况(题目已保证时间点唯一)
    • 考虑n或m为1的极端情况
  2. 变量范围问题

    • current可能的最大值是n(所有客人都进入但没人离开)
    • 使用int足够,无需long long
  3. 调试建议

    • 可以先用小规模数据测试,比如:
      3 in 1 out 3 in 5 2 2 4
      预期输出应为1(时刻2有1人),1(时刻4有1人)

4.3 算法扩展思考

这道题可以有多种变体,掌握核心思路后可以举一反三:

  1. 时间段查询: 如果询问改为时间段[y1, y2]内的最大/最小人数,该如何修改算法? (提示:需要维护更多状态,可能要用到线段树)

  2. 重复时间点: 如果允许in/out发生在同一时间点,该如何处理? (提示:需要定义事件优先级,通常out优先于in)

  3. 带权人数: 如果每个客人有权重,要求计算总权重而非人数,该如何修改? (提示:current改为累加权重即可)

5. 信奥刷题的系统性方法

5.1 如何高效刷题

  1. 题目分类训练

    • 将题目按算法类型分类(排序、搜索、DP、图论等)
    • 每个阶段集中攻克一类题目,建立思维模式
  2. 三步刷题法

    • 第一步:独立思考和尝试,至少30分钟
    • 第二步:查阅题解,理解优秀解法
    • 第三步:独立实现,并记录解题要点
  3. 错题管理

    • 建立错题本,记录错误原因和正确解法
    • 定期重做错题,确保真正掌握

5.2 C++在信奥中的优势

  1. STL的强大支持

    • vector:动态数组
    • set/map:红黑树实现的有序集合
    • unordered_set/unordered_map:哈希实现的快速查找
    • priority_queue:优先队列(堆)
  2. 性能优势

    • 相比Python等解释型语言,C++执行速度更快
    • 对于时间限制严格的题目,C++更容易通过
  3. 底层控制能力

    • 可以直接操作内存
    • 可以精细控制数据结构
    • 适合实现复杂算法

5.3 推荐的学习资源

  1. 在线评测平台

    • 洛谷(www.luogu.com.cn)
    • Codeforces(codeforces.com)
    • LeetCode(leetcode.cn)
  2. 经典教材

    • 《算法竞赛入门经典》(刘汝佳)
    • 《挑战程序设计竞赛》(秋叶拓哉)
    • 《算法导论》(Thomas H. Cormen)
  3. 实用工具

    • Visual Studio Code + C++插件
    • C++ Reference(cppreference.com)
    • 算法可视化网站(visualgo.net)

6. 从这道题看信奥考察重点

通过这道P5133 tb148题目,我们可以看出信息学竞赛的几个核心考察点:

  1. 问题抽象能力: 将实际场景抽象为计算模型的能力。这道题中,我们需要把客人进出记录抽象为时间线上的事件点。

  2. 算法选择能力: 面对一个问题,能快速判断适用算法的能力。暴力解法与扫描线算法在这道题中的效率差异巨大。

  3. 编码实现能力: 将算法准确转化为代码的能力。包括数据结构的设计、边界条件的处理等。

  4. 优化意识: 对算法时间/空间复杂度的敏感度。优秀的选手会在编码前就评估算法的可行性。

在实际比赛中,这类模拟题通常作为中等难度题目出现,既考察基础编码能力,也考察对算法的理解和应用能力。建议初学者从这类题目开始训练,逐步建立算法思维和编码习惯。

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

沐曦C500+CubeStudio大模型全流程实操指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 21:27:12

JAVA毕设项目:基于SpringBoot的作业批改服务平台的搭建与实现 基于SpringBoot+Vue的作业提交与批改系统 (源码+文档,讲解、调试运行,定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/9/11 21:23:28

ResNet18网络实战指南:结构拆解、PyTorch训练与避坑技巧

简介&#xff1a;ResNet18 是深度残差网络中结构精简且常用的 18 层 CNN 模型&#xff0c;由何恺明等人提出&#xff0c;适合希望在图像分类、特征提取等视觉任务中快速上手的初学者&#xff0c;以及需要在嵌入式或移动端部署轻量级网络的开发者。资源包仅 3 个文件&#xff0c…

作者头像 李华