news 2026/6/2 7:38:44

小明的账单(信息学奥赛一本通- P1372)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
小明的账单(信息学奥赛一本通- P1372)

【题目描述】

小明在一次聚会中,不慎遗失了自己的钱包,在接下来的日子,面对小明的将是一系列的补卡手续和堆积的账单… 在小明的百般恳求下,老板最终同意延缓账单的支付时间。可老板又提出,必须从目前还没有支付的所有账单中选出面额最大和最小的两张,并把他们付清。还没有支付的账单会被保留到下一天。 请你帮他计算出支付的顺序。

【输入】

第1行:一个正整数N(N≤15,000),表示小明补办银联卡总共的天数。

第2行到第N+1 行:每一行描述一天中收到的帐单。先是一个非负整数M≤100,表示当天收到的账单数,后跟M个正整数(都小于1,000,000,000),表示每张帐单的面额。

输入数据保证每天都可以支付两张帐单。

【输出】

输出共N 行,每行两个用空格分隔的整数,分别表示当天支付的面额最小和最大的支票的面额。

【输入样例】

4 3 3 6 5 2 8 2 3 7 1 7 0

【输出样例】

3 6 2 8 1 7 5 7

这是一个非常经典的“动态维护极值”问题。既然题目不难,我们直接切入重点,对比两种解法的优劣和核心技巧。

1. 题目本质

我们需要维护一个账单池,支持以下三种操作,且每天都要执行:

  1. Insert:插入若干个新数值。

  2. Pop Max:查询并删除最大值。

  3. Pop Min:查询并删除最小值。


2. 解法一:STL Multiset(最简捷)

利用 C++multiset底层红黑树自动排序的特性,它是解决此类问题的“万能钥匙”。

  • 思路:所有数据丢进去,它自动排好序。

    • 最小值:*st.begin()

    • 最大值:*st.rbegin()

  • 代码优势:极短,逻辑极其简单,不易出错。

  • 关键避坑

    • 删除时必须用迭代器st.erase(it),绝不能用st.erase(val)。后者会把所有同金额的账单一次性删光,导致 BUG。

    • 删除最大值推荐用st.erase(prev(st.end()))


3. 解法二:双堆 + 懒惰删除(最高效)

利用两个优先队列分别维护最大值和最小值。这是解决“堆不支持随机删除”的标准范式。

  • 思路

    • 双倍存储:每个账单同时进入maxqminq,并绑定唯一id

    • 懒惰删除 (Lazy Deletion):

      当我们在 maxq 删除了一个元素,无法直接去 minq 里删它(太慢)。

      于是我们在 deleted 数组里标记该 id 为“已删除”。

      等到 minq 的堆顶恰好浮现出这个“已删除”的元素时,再把它弹出丢掉。

  • 工程细节

    • while循环清理“死元素”时,最好加上!q.empty()防止越界(虽然本题数据保证不空,但这是好习惯)。


4. 总结与对比

维度Multiset 解法双堆 + 懒惰删除 解法
代码量极少中等
思维难度无脑需理解延迟删除
运行效率较慢 (红黑树常数大)极快(堆操作常数小)
适用场景比赛省时间、数据量中等卡常数、追求极致性能

完整代码

/* //直接用multiset 可以直接得到最大值和最小值 #include <iostream> #include <set>//必须包含这个头文件 #include <algorithm> using namespace std; //使用multiset,因为它会自动排序,且允许有重复的账单金额 multiset<int>st; int main(){ ios::sync_with_stdio(false); cin.tie(0); int n; cin>>n; for(int i=1;i<=n;i++){ int cnt;cin>>cnt; //1.把今天的账单全部扔进set for(int j=1;j<=cnt;j++){ int tmp; cin>>tmp; st.insert(tmp);//O(log N)自动排序 } //2.取出并删除最小值 //st.begin()就是最小值的迭代器 int mi=*st.begin(); st.erase(st.begin());//注意:要用迭代器删除,否则会删除所有等于mi的元素 //3.取出并删除最大值 //st.rbegin()是反向迭代器的开始,指向最大值 //或者用prev(st.end())也可以找到最大值 int ma=*st.rbegin(); //删除最大值(需要将反向迭代器转为正向迭代器,或者直接删除尾部前一个) //最简单的写法是删除迭代器:prev(st.end())指向最后一个元素 st.erase(prev(st.end())); //输出 cout<<mi<<" "<<ma<<"\n"; } return 0; } */ //用优先队列 #include <iostream> #include <queue> using namespace std; int deleted[1500001]; priority_queue<pair<int,int>> maxq;//默认最大堆 priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> minq;//最小堆 int main(){ ios::sync_with_stdio(false); cin.tie(0); int n; cin>>n; int id=0; for(int i=1;i<=n;i++){//总共有n天 int cnt;//每天有cnt张账单 cin>>cnt; for(int j=1;j<=cnt;j++){ int val; cin>>val; id++; maxq.push({val,id}); minq.push({val,id}); } while(!maxq.empty() && deleted[maxq.top().second]==1){//如果最大堆堆顶的数的id已经被标记为在最小堆里删除了,就直接弹出 maxq.pop();//如果最大堆堆顶的数的id已经被标记为在最小堆里删除了,就直接弹出 } int ma=maxq.top().first;//最大堆的最大值 deleted[maxq.top().second]=1;//标记这个最大值的id为1(已被删除,后面不能被最小堆拿来用了) maxq.pop();//把最大堆的最大值弹出 while(!minq.empty() && deleted[minq.top().second]==1){//如果最小堆堆顶的数的id已经被标记为在最大堆里删除了,就直接弹出 minq.pop();//如果最小堆堆顶的数的id已经被标记为在最大堆里删除了,就直接弹出 } int mi=minq.top().first;//最小堆的最小值 deleted[minq.top().second]=1;//标记这个最小值的id为1(已被删除,后面不能被最大堆拿来用了) minq.pop(); cout<<mi<<" "<<ma<<" "<<"\n"; } return 0; }

在比赛中,如果时间允许(N<=10^5),优先用 Multiset ;如果数据量极大或时限很紧,必须掌握双堆+懒惰删除。

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

Krita AI绘画工具配置全攻略:从新手到高手的场景化解决方案

你是不是也曾经面对过这样的困扰&#xff1a;想要在Krita中体验AI绘画的魔力&#xff0c;却被复杂的配置步骤劝退&#xff1f;或者安装过程中遇到了各种奇怪的问题&#xff0c;最终只能无奈放弃&#xff1f;别担心&#xff0c;今天我们就来彻底解决这些问题&#xff01; 【免费…

作者头像 李华
网站建设 2026/6/2 4:09:21

Open-AutoGLM一键部署方案曝光(附完整脚本与配置模板)

第一章&#xff1a;Open-AutoGLM一键部署方案概述Open-AutoGLM 是面向大语言模型自动化任务的一站式开源工具&#xff0c;支持从模型加载、推理优化到服务部署的全流程快速搭建。其一键部署方案极大降低了开发者在本地或云端运行 GLM 系列模型的技术门槛&#xff0c;适用于科研…

作者头像 李华
网站建设 2026/6/1 23:26:41

解锁QQ音乐加密文件:qmcdump解码工具完整指南

解锁QQ音乐加密文件&#xff1a;qmcdump解码工具完整指南 【免费下载链接】qmcdump 一个简单的QQ音乐解码&#xff08;qmcflac/qmc0/qmc3 转 flac/mp3&#xff09;&#xff0c;仅为个人学习参考用。 项目地址: https://gitcode.com/gh_mirrors/qm/qmcdump 你是否曾经从Q…

作者头像 李华
网站建设 2026/6/1 23:19:42

AdGuardHomeRules:打造纯净网络体验的终极广告拦截方案

在网络世界中&#xff0c;广告无处不在&#xff0c;它们不仅干扰我们的浏览体验&#xff0c;还可能带来安全风险。AdGuardHomeRules作为一款强大的开源广告拦截规则集&#xff0c;能够彻底解决这些问题&#xff0c;为你的所有联网设备提供全面的广告防护。 【免费下载链接】AdG…

作者头像 李华
网站建设 2026/6/1 6:19:58

GPU资源不足也能部署?Open-AutoGLM轻量化方案全解析,立即掌握

第一章&#xff1a;GPU资源不足也能部署&#xff1f;Open-AutoGLM的轻量化破局之道在边缘计算和本地化部署需求日益增长的背景下&#xff0c;大模型的高显存占用成为落地瓶颈。Open-AutoGLM 通过一系列轻量化设计&#xff0c;使用户即便在仅有4GB显存的消费级GPU上也能高效运行…

作者头像 李华
网站建设 2026/6/2 5:25:32

为什么顶尖团队都在抢用Open-AutoGLM云手机?3大颠覆性优势曝光

第一章&#xff1a;Shell脚本的基本语法和命令Shell脚本是Linux/Unix系统中自动化任务的核心工具&#xff0c;通过编写可执行的文本文件&#xff0c;用户能够组合命令、控制流程并处理数据。Shell脚本通常以#!/bin/bash开头&#xff0c;称为Shebang&#xff0c;用于指定解释器路…

作者头像 李华