csp信奥赛C++标准模板库STL案例应用7

csp信奥赛C++标准模板库STL案例应用7

set实践

题目描述

Tiger 最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。

Tiger 拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况:当最小波动值越大时,就说明营业情况越不稳定。

而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助 Tiger 来计算这一个值。

我们定义,一天的最小波动值 = min ⁡ { ∣ 该天以前某一天的营业额 − 该天营业额 ∣ } \min\{|\text{该天以前某一天的营业额}-\text{该天营业额}|\} min{∣该天以前某一天的营业额−该天营业额∣}。

特别地,第一天的最小波动值为第一天的营业额。

输入格式

第一行为正整数 n n n( n ≤ 32767 n \leq 32767 n≤32767) ,表示该公司从成立一直到现在的天数,接下来的 n n n 行每行有一个整数 a i a_i ai( ∣ a i ∣ ≤ 1 0 6 |a_i| \leq 10^6 ∣ai∣≤106) ,表示第 i i i 天公司的营业额,可能存在负数。

输出格式

输出一个整数,即每一天最小波动值的和,保证结果小于 2 31 2^{31} 231。

输入输出样例 1
输入 1
复制代码
6
5
1
2
5
4
6
输出 1
复制代码
12
说明/提示

结果说明: 5 + ∣ 1 − 5 ∣ + ∣ 2 − 1 ∣ + ∣ 5 − 5 ∣ + ∣ 4 − 5 ∣ + ∣ 6 − 5 ∣ = 5 + 4 + 1 + 0 + 1 + 1 = 12 5+|1-5|+|2-1|+|5-5|+|4-5|+|6-5|=5+4+1+0+1+1=12 5+∣1−5∣+∣2−1∣+∣5−5∣+∣4−5∣+∣6−5∣=5+4+1+0+1+1=12

思路分析

本题要求计算每天营业额的最小波动值之和。对于第 i 天的营业额,需要在之前的所有营业额中找到与它最接近的值(前驱或后继),计算差的绝对值。

核心思想
  1. 使用平衡二叉搜索树(这里用 C++ 的 set)来维护之前的所有营业额
  2. 对于每个新的营业额:
    • lower_bound 找到第一个大于等于当前值的位置
    • 这个位置和它前一个位置(如果存在)就是与当前值最接近的两个候选值
    • 取这两个值与当前值差的最小值作为当天的最小波动值
  3. 第一天特殊处理,最小波动值就是当天的营业额
时间复杂度
  • 使用 set 每次插入和查询都是 O(log n)
  • 总时间复杂度:O(n log n),n ≤ 32767,可以接受

代码实现

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int n, sum = 0;  // n: 天数,sum: 最小波动值总和
set<int> s;      // 用set存储之前的营业额,自动排序

int main() {
    cin >> n;
    
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;  // 读取当天的营业额
        
        // 如果是第一天,特殊处理
        if (s.empty()) {
            sum += x;      // 第一天最小波动值就是营业额本身
            s.insert(x);   // 加入集合
            continue;
        }
        
        // 使用lower_bound找到第一个大于等于x的位置
        auto it = s.lower_bound(x);
        int ans = INT_MAX;  // 初始化最小差值为最大整数
        
        // 检查后继(如果存在)
        if (it != s.end()) {
            ans = min(ans, abs(*it - x));
        }
        
        // 检查前驱(如果存在)
        if (it != s.begin()) {
            it--;  // 移动到前一个位置
            ans = min(ans, abs(*it - x));
        }
        
        // 累加当天的最小波动值
        sum += ans;
        // 将当天营业额加入集合,供后续使用
        s.insert(x);
    }
    
    cout << sum;
    return 0;
}

功能分析

1. 数据结构选择
  • 使用 set<int>:自动排序,可以快速查找前驱和后继
  • 基于红黑树实现,插入和查找都是 O(log n) 时间复杂度
2. 算法流程
  1. 初始化:读取天数 n,初始化总和 sum 和集合 s
  2. 处理每一天
    • 读取当天营业额 x
    • 如果集合为空(第一天),直接累加 x
    • 否则,查找 x 在集合中的插入位置:
      • 查找第一个 ≥ x 的数(后继)
      • 查找第一个 < x 的数(前驱)
      • 取两者与 x 差的最小值
    • 累加到总和
    • 将 x 插入集合
  3. 输出结果:输出总和 sum
3. 关键点
  • lower_bound(x) 返回第一个 ≥ x 的迭代器
  • 如果 lower_bound 返回 end(),说明没有 ≥ x 的数
  • 前驱检查:it != s.begin() 确保有前一个元素
  • 第一天特殊处理:最小波动值 = 当天营业额
4. 示例解析

输入:

复制代码
6
5 1 2 5 4 6

处理过程:

  • 第1天:sum=5,集合={5}
  • 第2天:x=1,前驱/后继:5,差值=4,sum=9,集合={1,5}
  • 第3天:x=2,前驱=1(差1),后继=5(差3),取1,sum=10,集合={1,2,5}
  • 第4天:x=5,找到相等的5,差=0,sum=10,集合={1,2,5}
  • 第5天:x=4,前驱=2(差2),后继=5(差1),取1,sum=11,集合={1,2,4,5}
  • 第6天:x=6,前驱=5(差1),无后继,取1,sum=12,集合={1,2,4,5,6}

各种学习资料,助力大家一站式学习和提升!!!

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"##########  一站式掌握信奥赛知识!  ##########";
	cout<<"#############  冲刺信奥赛拿奖!  #############";
	cout<<"######  课程购买后永久学习,不受限制!   ######";
	return 0;
}
  • 一、CSP信奥赛C++通关学习视频课:
    • C++语法基础
    • C++语法进阶
    • C++算法
    • C++数据结构
    • CSP信奥赛数学
    • CSP信奥赛STL
  • 二、CSP信奥赛C++竞赛拿奖视频课:
    • 信奥赛csp-j初赛高频考点解析
    • CSP信奥赛C++复赛集训课(12大高频考点专题集训)
  • 三、考级、竞赛刷题题单及题解:
    • GESP C++考级真题题解
    • CSP信奥赛C++初赛及复赛高频考点真题解析
    • CSP信奥赛C++一等奖通关刷题题单及题解

详细内容:

1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):

https://edu.csdn.net/lecturer/7901 点击跳转


2、CSP信奥赛C++竞赛拿奖视频课:

https://edu.csdn.net/course/detail/40437 点击跳转

3、csp信奥赛冲刺一等奖有效刷题题解:

CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新):https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转

  • 2025 csp-j 复赛真题及答案解析(最新更新)
  • 2025 csp-x(山东) 复赛真题及答案解析(最新更新)
  • 2025 csp-x(河南) 复赛真题及答案解析(最新更新)
  • 2025 csp-x(辽宁) 复赛真题及答案解析(最新更新)
  • 2025 csp-x(江西) 复赛真题及答案解析(最新更新)
  • 2025 csp-x(广西) 复赛真题及答案解析(最新更新)
  • 2020 ~ 2024 csp 复赛真题题单及题解
  • 2019 ~ 2022 csp-j 初赛高频考点真题分类解析
  • 2021 ~ 2024 csp-s 初赛高频考点解析
  • 2023 ~ 2024 csp-x (山东)初赛真题及答案解析
  • 2024 csp-j 初赛真题及答案解析
  • 2025 csp-j 初赛真题及答案解析(最新更新)
  • 2025 csp-s 初赛真题及答案解析(最新更新)
  • 2025 csp-x (山东)初赛真题及答案解析(最新更新)
  • 2025 csp-x (江西)初赛真题及答案解析(最新更新)
  • 2025 csp-x (辽宁)初赛真题及答案解析(最新更新)

CSP信奥赛C++一等奖通关刷题题单及题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转

  • 129 道刷题练习和详细题解,涉及:模拟算法、数学思维、二分算法、 前缀和、差分、深搜、广搜、DP专题、 树和图

4、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

· 文末祝福 ·

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"跟着王老师一起学习信奥赛C++";
	cout<<"    成就更好的自己!       ";
	cout<<"  csp信奥赛一等奖属于你!   ";
	return 0;
}
相关推荐
༾冬瓜大侠༿2 小时前
C++内存和模板
java·开发语言·c++
LXS_35711 小时前
Day 18 C++提高 之 STL常用容器(string、vector、deque)
开发语言·c++·笔记·学习方法·改行学it
deng-c-f12 小时前
Linux C/C++ 学习日记(53):原子操作(二):实现shared_ptr
开发语言·c++·学习
一个不知名程序员www12 小时前
算法学习入门---结构体和类(C++)
c++·算法
墨雪不会编程13 小时前
C++ string 详解:STL 字符串容器的使用技巧
java·开发语言·c++
yangpipi-14 小时前
《C++并发编程实战》第5章 C++内存模型和原子操作
android·java·c++
SunkingYang14 小时前
MFC进程间消息通信深度解析:SendMessage、PostMessage与SendNotifyMessage的底层实现与实战指南
c++·mfc·共享内存·通信·postmessage·sendmessage·进程间
XFF不秃头15 小时前
力扣刷题笔记-旋转图像
c++·笔记·算法·leetcode
王老师青少年编程15 小时前
csp信奥赛C++标准模板库STL案例应用3
c++·算法·stl·csp·信奥赛·lower_bound·标准模版库