洛谷 B4450 / B3867 / B3923 智慧购物、储蓄与做题——从程序到生活

洛谷 B4450 / B3867 / B3923 智慧购物、储蓄与做题------从程序到生活

📌 摘要

B4450 用数组追踪每种文具的最低价,B3867 用数组累加每个储蓄罐的存款,B3923 用三变量滚动模拟斐波那契式做题计划并设终止条件。三道题都以"小杨的日常生活"为背景------购物、存钱、学习------恰好覆盖了最常见的三类应用需求:比价、记账、计划 。三道题共享一个数据结构------数组 ------分别用作"最小值追踪器"、"累加器"和"滚动窗口"。本文从伪代码题解出发,延伸到这些算法模式如何变成真实应用:比价网站(淘宝/京东的最低价筛选)、记账软件(支付宝/微信账单)、习惯养成 App------你在洛谷上写的 a[k]=pans[a]+=i,在工业界是比价引擎和个人金融系统的核心逻辑。

题目链接B4450 小杨的智慧购物 | B3867 小杨的储蓄 | B3923 小杨做题

📚 目录

  • [📝 前言](#📝 前言)

  • [🔍 三道题在考什么](#🔍 三道题在考什么)

  • [🛒 B4450:小杨的智慧购物](#🛒 B4450:小杨的智慧购物)

    • [💡 思路](#💡 思路)

    • [📝 伪代码](#📝 伪代码)

    • [🎯 关键点](#🎯 关键点)

  • [💰 B3867:小杨的储蓄](#💰 B3867:小杨的储蓄)

    • [💡 思路](#💡 思路)

    • [📝 伪代码](#📝 伪代码)

    • [🎯 关键点](#🎯 关键点)

  • [📚 B3923:小杨做题](#📚 B3923:小杨做题)

    • [💡 思路](#💡 思路)

    • [📝 伪代码](#📝 伪代码)

    • [🎯 关键点](#🎯 关键点)

  • [⚖️ 三题对比](#⚖️ 三题对比)

  • [⚠️ 注意事项](#⚠️ 注意事项)

  • [🌳 延伸:从程序到生活------算法模式如何变成应用](#🌳 延伸:从程序到生活——算法模式如何变成应用)

    • [🛒 比价与最低价追踪](#🛒 比价与最低价追踪)

    • [💰 累加器模式:记账与储蓄](#💰 累加器模式:记账与储蓄)

    • [📈 斐波那契式增长:习惯与复利](#📈 斐波那契式增长:习惯与复利)

    • [📊 数组------从考试题到数据库](#📊 数组——从考试题到数据库)

    • [🏠 三道题的现实映射](#🏠 三道题的现实映射)

  • [📚 延伸阅读文献](#📚 延伸阅读文献)


📝 前言

这篇题解没有源代码,只有伪代码。

作为一名信奥教练,我不提倡复制粘贴。我见过太多学生搜到题解、复制、粘贴、提交、AC------代码跑通了,脑子没跑通。下次遇到变体题,还是不会。

伪代码剥掉了语言的壳,只留算法的骨架。你看不到 #include,看不到 cincout,看不到那些让你以为"我会了"的语法细节。你能看到的只有:这一步做什么、下一步做什么、为什么这么做。

如果你是路过的友友,已经在这道题上挣扎了很久------先去喝杯水,回来重新看看自己卡在哪一步。是没读懂题意?是思路方向偏了?还是代码有 bug 但逻辑其实对?大多数时候不是不会,是走偏了。偏了不可怕,可怕的是偏了之后直接放弃,去抄一份能 AC 的代码。抄完你以为你懂了,其实你只是搬了别人的结论。

除非你时间真的紧张------比赛临近、作业要交------那种情况先 AC 再说,能理解。但平时练习,给自己一点耐心。先自己想、自己写、自己调,跑不过了再来看伪代码:你的思路和这里差在哪一步。那一步,就是你真正学到的东西。


🔍 三道题在考什么

三道题都以"小杨的日常生活"为背景,但考察的算法模式截然不同:

B4450 智慧购物 B3867 储蓄 B3923 做题
生活场景 买文具找最低价 每天往储蓄罐存钱 按斐波那契式计划做题
数组用途 最小值追踪器 累加器 ---(三变量滚动)
核心操作 a[k]=min(a[k],p) ans[a]+=i a,b,sum 三变量递推
算法模式 分组取最小 分组累加 递推 + 提前终止
现实对应 比价网站 记账软件 习惯养成 App

B4450 用数组下标当"种类编号",数组值存该种类的最低价------每来一件新商品,比较并更新。

B3867 用数组下标当"储蓄罐编号",数组值存该罐的总金额------每来一天,把天号(等于金额)累加进去。

B3923 不用数组,用三个变量滚动模拟斐波那契式序列,到达阈值就停。

三道题对应了三种最基本的程序模式:选择(取最小)、累积(加起来)、递推(用前项算后项)。这三种模式覆盖了日常生活中 80% 的计算需求。


🛒 B4450:小杨的智慧购物

💡 B4450 思路

M 种文具,N 件商品。对每件商品(种类 k,价格 p),更新种类 k 的最低价。最后把 M 个种类的最低价加起来。

数组 a[k] 用种类编号 k 做下标,存该种类目前的最低价。初始化为 0(表示还没见过该种类)。读入一件商品时:如果 a[k]==0(第一次见),设为 p;如果 a[k]>p(更便宜),更新为 p。

📝 B4450 伪代码

text 复制代码
读取 M, N
数组 a[1..M] 初始化为 0         // a[k] = 种类 k 的最低价

对 i = 1 到 N:
    读取 k, p
    如果 a[k] == 0:              // 第一次见到这个种类
        a[k] = p
    如果 a[k] > p:              // 比已知的更便宜
        a[k] = p

总价 = 0
对 k = 1 到 M:
    总价 += a[k]                // 每种种类的最低价求和

输出 总价

🎯 B4450 关键点

数组下标 = 种类编号。 这是数组最强大的用法之一------用下标直接索引到对应类别,O(1) 查找和更新。不需要遍历搜索。

a[k]==0 的"首次"判断。 初始值为 0 表示"未见过"。第一次遇到种类 k 时 a[k]==0,设为 p。之后只做 a[k]>p 的比较。因为价格 ≥1,0 永远不会被误认为有效价格。

用样例追踪:

输入 a1 a2 说明
1 1 1 0 种类1首次,价格1
1 2 1 0 2>1,不更新
1 1 1 0 1不<1,不更新
2 3 1 3 种类2首次,价格3
2 10 1 3 10>3,不更新

总价 = a1+a2 = 1+3 = 4

"分组取最小"模式。 这道题的本质是:把 N 件商品按种类分组,每组取最小值,再求和。在数据处理中这是 GROUP BY + MIN + SUM 的模式------SQL 里的一行聚合查询。


💰 B3867:小杨的储蓄

💡 B3867 思路

N 个储蓄罐编号 0 到 N-1。第 i 天往储蓄罐 a_i 里存 i 元。D 天后输出每个储蓄罐的总金额。

数组 ans[a] 用储蓄罐编号做下标,每来一天把天号 i(等于存入金额)累加进去。

📝 B3867 伪代码

text 复制代码
读取 N, D
数组 ans[0..N-1] 初始化为 0     // ans[j] = 储蓄罐 j 的总金额

对 i = 1 到 D:                   // 第 i 天
    读取 a                       // 今天选的储蓄罐编号
    ans[a] += i                  // 存入 i 元(天号 = 金额)

对 j = 0 到 N-1:
    输出 ans[j],后跟空格

🎯 B3867 关键点

累加器模式。 ans[a] += i 一行代码完成了"找到对应储蓄罐"和"累加金额"两个操作。数组下标直接定位储蓄罐,不需要搜索。

用样例 1 追踪(N=2, D=3, 选择序列 0,1,0):

天 i 储蓄罐 a 操作 ans0 ans1
1 0 ans0 += 1 1 0
2 1 ans1 += 2 1 2
3 0 ans0 += 3 4 2

输出:4 2

天号 = 金额。 第 i 天存 i 元------题目把"天数"和"金额"巧妙地绑定在一起。ans[a] += i 中的 i 既是循环计数器又是存入金额,一行代码两个用途。

0 号编号。 储蓄罐从 0 开始编号,不是 1。输出也从 0 号开始。这是 C/C++ 的习惯------数组下标从 0 开始。


📚 B3923:小杨做题

💡 B3923 思路

第 1 天做 a 题,第 2 天做 b 题,第 3 天起每天 = 前两天之和(斐波那契式)。如果某天做了 ≥ m 题,之后不再做题。求 N 天内总共做了多少题。

用三个变量 a(前前天)、b(前天)、sum(今天)滚动递推。每天做完后检查 b >= m 是否满足终止条件。

📝 B3923 伪代码

text 复制代码
读取 a, b, m, N
total = 0
sum = 0

对 i = 1 到 N:
    如果 i == 1:
        sum = a                    // 第1天
        total += a
    否则如果 i == 2:
        sum = sum + b              // 第2天,sum 此时 = a + b
        total += b
    否则:                           // 第3天起
        a = b                      // 滚动:前前天 = 原前天
        b = sum                    // 滚动:前天 = 原今天
        sum = a + b                // 今天 = 前前天 + 前天
        total += b                 // 累加今天做的题数

    如果 b >= m:                    // 达到阈值,停止
        跳出循环

输出 total

🎯 B3923 关键点

三变量滚动。 斐波那契式序列只需要前两项,不需要存整个序列。用 absum 三个变量滚动------每次迭代把 b 传给 asum 传给 b、新值传给 sum。空间 O(1)。

用样例 1 追踪(a=1, b=2, m=10, N=5):

天 i a(前前) b(前) sum(今) 做的题 total b≥m?
1 1 2 1 1 1 2<10
2 1 2 3 2 3 2<10
3 2 3 5 3 6 3<10
4 3 5 8 5 11 5<10
5 5 8 13 8 19 8<10

输出:19。序列 1, 2, 3, 5, 8 是斐波那契式(每项 = 前两项之和)。

提前终止。 样例 2(a=1, b=1, m=5, N=8):第 5 天做了 5 题 ≥ m=5,break。total=1+1+2+3+5=12 。N=8 但只做了 5 天------break 跳出循环,后面的天不做也不加。

"b >= m"的检查时机。 检查在每天做完之后------当天做到 ≥m 题仍然算入 total,但从第二天起不做题。如果题目改成"做到 ≥m 题当天就不算",检查要移到累加之前。

🔧 两个建议修复的隐患。 原始代码有两个依赖"碰巧"才正确的写法,建议显式修复:

隐患 原始代码 问题 建议修复
sum 未初始化 int sum; 局部变量不初始化,值未定义。碰巧为 0 才正确 int sum = 0;
第 1 天用 += sum += a; 依赖 sum 初始为 0。如果 sum 有垃圾值,结果错 sum = a;(设值,不是累加)

修复后的第 1-2 天逻辑:

text 复制代码
如果 i == 1:
    sum = a               // 设值,不是累加
    total += a
否则如果 i == 2:
    sum = a + b           // 直接算 a+b,不依赖上一步
    total += b

为什么原代码"碰巧"能过? 因为大多数编译器在非优化模式下把未初始化的局部变量零初始化(sum 碰巧为 0),所以 sum += a 等价于 sum = 0 + a = a。但这是未定义行为 ------C++ 标准不保证未初始化变量为 0。换一个编译器或开优化,可能就错了。考试能过不代表代码正确。


⚖️ 三题对比

B4450 智慧购物 B3867 储蓄 B3923 做题
数组用途 最小值追踪 累加器 不用数组(三变量滚动)
核心操作 a[k] = min(a[k], p) ans[a] += i sum = a + b 滚动
算法模式 分组取最小 分组累加 递推 + 提前终止
数组大小 O(M) O(N) O(1)
时间复杂度 O(N) O(D) O(min(N, 终止天))
生活场景 购物比价 存钱记账 学习计划
现实对应 比价网站 记账软件 习惯养成 App

B4450 和 B3867 都用数组做"分组"------一个按下标分组取最小,一个按下标分组累加。B3923 不需要分组,只需要递推。三种模式覆盖了日常计算的三种基本需求:选择最优、累积总量、预测趋势


⚠️ 注意事项

  • B4450 的 a[k]==0 判断 :用 0 表示"未见过",因为价格 ≥1。如果价格可能为 0,需要换一个哨兵值(如 -1 或 INT_MAX)。

  • B4450 的 long long :M≤10⁵,每个最低价≤10³,总价最多 10⁸------int 能存(上限约 2×10⁹),但用 long long 更安全。

  • B3867 的 0 号编号:储蓄罐从 0 开始,输出也从 0 号开始。如果习惯从 1 开始编号,容易搞错。

  • B3923 的 sum 未初始化 :原始代码中 sum 声明后未赋初值,依赖编译器零初始化。虽然实际能过,但这是未定义行为 ------建议显式初始化 sum = 0

  • B3923 的 sum += a vs sum = a :第一行用 += 而非 =,依赖 sum 初始为 0。如果 sum 有垃圾值,结果就错了。第一行应该是 sum = a(设值),不是 sum += a(累加)。

  • B3923 的终止条件位置if(b >= m) break 在循环体末尾------当天做的题仍然算入 total,从下一天起停止。如果题意是"当天达到 m 就不算",需要调整位置。


🌳 延伸:从程序到生活------算法模式如何变成应用

你说这三道题"从程序到生活,到贴近生活,让日常更为便捷的应用需求的出现"。没错------三道题的算法模式分别对应了三种最常见的日常应用:比价、记账、计划。你在洛谷上写的几行代码,在工业界是真实产品的核心逻辑。

🛒 比价与最低价追踪

B4450 的 a[k] = min(a[k], p) 做的事是:对每个商品类别,追踪最低价。这正是比价网站的核心算法。

应用 做什么 和 B4450 的对应
淘宝/京东"价格筛选" 用户选"价格从低到高",对每类商品显示最低价 a[k] = min(a[k], p)
什么值得买 跨平台比价,追踪历史最低价 a[k] 存历史最低,新价格来了比较
Google Shopping 跨商家比价,按类别分组 GROUP BY 类别 + MIN(价格)
航旅纵横/携程"最低票价" 对每条航线追踪最低票价 a[航线] = min(a[航线], 当前票价)

B4450 的数据规模是 N=10⁵,O(N) 一趟扫完。真实比价网站的数据规模是 N=10⁸(全国商品),用同样的算法但加了分布式存储和缓存。算法不变,规模变了一千倍。

比价网站的技术栈:爬虫抓取商品数据 → 按类别分组存入数据库(a[k] 变成了数据库表的一行)→ 查询时取每类最低价(SELECT MIN(price) FROM products GROUP BY category)→ 前端展示。你在 B4450 里用一个 for 循环做的事,比价网站用一条 SQL 查询做同样的事。

💰 累加器模式:记账与储蓄

B3867 的 ans[a] += i 做的事是:对每个储蓄罐,累加每次存入的金额。这是记账软件的核心模式。

应用 做什么 和 B3867 的对应
支付宝/微信账单 按类别(餐饮/交通/购物)累加支出 ans[类别] += 金额
银行系统 按账户累加存取款 ans[账户号] += 交易额
家庭记账 App 按成员/类别/月份分组累加 ans[维度] += 金额
健身 App 按日期/运动类型累加卡路里 ans[日期] += 消耗量

B3867 中"天号 = 金额"的设定,在记账软件里变成了"时间戳 = 交易时间,金额 = 交易额"------两者解耦了,但累加逻辑一样:account[target] += amount

记账软件的技术栈:用户记录每笔交易 → 按维度(类别/日期/账户)分组累加 → 生成报表。你在 B3867 里用 ans[a] += i 一行做的事,记账软件用数据库的 SUM(amount) GROUP BY category 做同样的事。

📈 斐波那契式增长:习惯与复利

B3923 的做题计划是斐波那契式增长------每天做的题数是前两天之和。这种"用前项推后项"的模式在生活规划中无处不在。

应用 做什么 和 B3923 的对应
习惯养成 App(如 Streaks) 逐日递增的习惯强度,达到目标后维持 递推 + 终止条件
学习计划工具 每天复习量按遗忘曲线递推 艾宾浩斯曲线(类似递推)
理财复利计算 每年收益 = 本金 × (1+利率),递推 N 年 total = total * (1+r)
健身计划(渐进超负荷) 每周重量 = 上周 + 增量 递推式增长

B3923 的斐波那契式增长在现实中不常见(没人真能每天做前一天 + 前前天量的题),但"递推 + 终止"的模式是所有计划类应用的底层逻辑:从初始状态出发,按规则推进,达到阈值就停。

番茄钟、背单词 App、健身记录器------都在做同样的事:一个循环,每步更新状态,检查终止条件。你在 B3923 里写的 for + break,在习惯养成 App 里是 while (未达成目标) + 更新进度

📊 数组------从考试题到数据库

三道题中 B4450 和 B3867 都用数组做"分组"。这不是巧合------数组是所有数据处理的基础结构

洛谷题 数组下标 数组值 数据库对应
B4450 种类编号 最低价 SELECT MIN(price) FROM products GROUP BY category
B3867 储蓄罐编号 总金额 SELECT SUM(amount) FROM transactions GROUP BY account
B3923 ---(三变量) --- 不需要数据库,单行递推

数组下标 = 数据库的 GROUP BY 键。数组值 = 数据库的聚合结果(MIN/SUM)。你在洛谷上用 a[k] 做的事,数据库用 GROUP BY 做------只是数据库帮你封装了循环和查找。

数组操作 C++ 代码 SQL 对应
分组取最小 if(a[k]>p) a[k]=p MIN(price) ... GROUP BY k
分组累加 ans[a] += i SUM(amount) ... GROUP BY a
遍历求和 sum += a[i] SUM(a[i])

数组的本质是什么? 是一个"按下标直接定位"的存储结构。数据库的索引做了同样的事------用 B+ 树把"按键查找"从 O(N) 优化到 O(log N)。你在 B4450 里用 a[k] 直接定位种类 k 的最低价,数据库用索引直接定位某个键的记录------思路一样,实现不同。

🏠 三道题的现实映射

把三道题和延伸放在一起:

洛谷题 算法模式 生活场景 真实应用 技术栈
B4450 分组取最小 购物比价 淘宝/什么值得买 爬虫 + 数据库 + SQL GROUP BY
B3867 分组累加 存钱记账 支付宝账单/银行系统 交易流水 + SUM GROUP BY
B3923 递推 + 终止 学习计划 习惯养成 App/番茄钟 状态机 + while 循环

三道题覆盖了日常应用的三种核心计算需求:选择最优(比价)、累积总量(记账)、预测趋势(计划) 。你在洛谷上写的 a[k]=min(a[k],p)ans[a]+=isum=a+b,在工业界分别变成了比价引擎、记账核心、计划调度器。算法不变,封装变了------从 for 循环变成了 SQL 查询和 API 调用,但核心逻辑一脉相承。

你今天在洛谷上帮小杨做的事------买最便宜的文具、算储蓄罐里有多少钱、按计划做题------和淘宝帮你比价、支付宝帮你记账、Streaks 帮你养成习惯,做的是同一件事:用程序让生活更便捷。


📚 延伸阅读文献

论文与技术文档
  1. E. F. Codd. A Relational Model of Data for Large Shared Data Banks. Communications of the ACM, 1970. ------ 关系数据库的奠基论文,GROUP BY + MIN/SUM 的理论基础。
  2. D. E. Knuth. The Art of Computer Programming, Vol. 1: Fundamental Algorithms (3rd Edition). Addison-Wesley, 1997. ------ 数组、链表等基础数据结构的权威论述。
在线资源
  1. 洛谷. B4450 GESP202512 三级 小杨的智慧购物 . https://www.luogu.com.cn/problem/B4450
  2. 洛谷. B3867 GESP202309 三级 小杨的储蓄 . https://www.luogu.com.cn/problem/B3867
  3. 洛谷. B3923 GESP202312 二级 小杨做题 . https://www.luogu.com.cn/problem/B3923
  4. SQL GROUP BY Tutorial --- W3Schools . https://www.w3schools.com/sql/sql_groupby.asp ------ SQL GROUP BY + MIN/SUM 聚合教程。
  5. Fibonacci Sequence --- Math is Fun . https://www.mathsisfun.com/numbers/fibonacci-sequence.html ------ 斐波那契序列入门。
  6. Database Indexing --- GeeksforGeeks . https://www.geeksforgeeks.org/database-indexing/ ------ 数据库索引原理,B+ 树与数组下标的关系。
  7. 价格比较网站 --- 维基百科 . (Price Comparison Service --- Wikipedia) ------ 比价网站的工作原理与历史。
  8. Personal Finance Software --- Wikipedia . (Personal Finance Software --- Wikipedia) ------ 个人记账软件的发展史。
推荐教材
  • T. H. Cormen, C. E. Leiserson, R. L. Rivest, C. Stein. Introduction to Algorithms (4th Edition). MIT Press, 2022. ------ 算法圣经,含数组、递推、聚合等基础内容。

  • H. Garcia-Molina, J. Ullman, J. Widom. Database Systems: The Complete Book (2nd Edition). Pearson, 2008. ------ 数据库系统教材,含 GROUP BY、索引、聚合查询。

  • R. Bird. Thinking Functionally with Haskell. Cambridge University Press, 2014. ------ 函数式编程视角的递推与累加,帮助理解算法模式的抽象。


本文标签:#算法 #数组 #分组取最小 #累加器 #斐波那契 #比价 #记账 #习惯养成 #洛谷题解 #信奥 #C++ #入门

本文首发于 CSDN,作者:HugoStudio_SWAN

相关推荐
a187927218311 小时前
【算法】动态规划第二篇:双序列 DP 三课——继承、计步与断链
算法·leetcode·动态规划·dp·回溯·暴力·算法讲解
江畔柳前堤2 小时前
前台·中台·后台:2026年AI原生时代的架构全景图
开发语言·人工智能·算法·机器学习·架构·scala·ai-native
职场的momo2 小时前
字节生活服务海量内推,挑战亿级订单与AI交易中台
人工智能·程序人生·面试·职场和发展·跳槽·生活·业界资讯
文心快码BaiduComate2 小时前
2026 OPC x AI Coding 趋势案例交流会圆满落幕:一个人就一支研发团队
算法
ACM-moran3 小时前
条件显化(二分单峰函数+构造数列)
算法·推公式·整数三分
会周易的程序员3 小时前
5Draft(五帝)测试报告
服务器·c++·分布式·raft·共识算法·共识·算力服务器
UIU1143 小时前
scanf与cout的误区:探究其内部的机制
c++·学习·c#·scanf
闻缺陷则喜何志丹3 小时前
【栈 运算系统】P3719 [AHOI2017初中组] rexp|普及+
c++·算法··洛谷·运算系统
疯狂打码的少年3 小时前
【数据库技术】多值依赖与第四范式(4NF)
数据库·笔记·算法