蓝桥杯备赛:Day4-P9749 公路

📚 算法笔记:P9749 CSP-J 2023 公路 (贪心与结余处理)

1. 题目简述

CSP-J 2023 公路 - 洛谷

你需要开车经过 N N N 个站点,站点间有固定距离。每个站点的油价不同,油箱无限大,每升油跑 D D D 公里。求跑完全程的最小花费。

  • 输入 :站点数 N N N、每升油公里数 D D D、站点间距离数组 r o a d road road、各站油价数组 m o n e y money money。
  • 输出 :最小总花费(long long)。

2. 核心代码 (C++ 实现)

c++ 复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 100005;
ll N, D;
ll road[MAXN];  // 存储第 i 到第 i+1 站的距离
ll money[MAXN]; // 存储第 i 站的油价

void solve() 
{
    if (!(cin >> N >> D)) return;
    
    for (int i = 1; i <= N - 1; i++) cin >> road[i];
    for (int i = 1; i <= N; i++) cin >> money[i];

    ll res = 0;               // 关键:之前加油后剩下的、还没跑完的"路程额度"
    ll ans = 0;               // 总花费
    ll min_price = money[1];  // 贪心核心:到目前为止遇到的最低油价

    for (int i = 1; i <= N - 1; i++) 
    {
        // 1. 每到一个新站,都尝试更新"历史最低油价"
        min_price = min(min_price, money[i]);

        // 2. 判断当前剩下的"油(路程额度)"够不够跑到下一站
        if (road[i] > res) 
        {
            ll need_dist = road[i] - res;      // 实际还需要补的路程
            ll buy_oil = (need_dist + D - 1) / D; // 向上取整计算需买几升油
            
            ans += buy_oil * min_price;        // 按历史最低价买入
            res = res + buy_oil * D - road[i]; // 更新剩余路程额度
        } 
        else 
        {
            res -= road[i]; // 够跑则直接扣除额度
        }
    }
    cout << ans << endl;
}

int main() 
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    solve();
    return 0;
}

3. 核心考点与注意事项

🔍 核心考点
  1. 单调贪心思想:我们不需要预知未来所有的油价。只要当前站点的油价比之前的"历史最低价"贵,我们就假装在那个最低价的车站多加了点油,直到遇到一个更便宜的车站为止。
  2. 向上取整技巧 :加油必须是整数升。使用 (a + b - 1) / b 实现 ⌈ a / b ⌉ \lceil a/b \rceil ⌈a/b⌉,避免了浮点数精度问题。(重点掌握)
  3. 余量维护 (res) :买 1 1 1 升油能跑 D D D 公里,但这段路可能只需要 D − 1 D-1 D−1 公里。多出来的 1 1 1 公里必须计入 res,并在计算下一段路时扣除,否则会产生巨额误差。
  4. "在第 i i i 站按 min_price 买油""在之前那个 min_price 站点多买一点开到第 i i i 站" ,在最后结算的总金额上是完全等价的。这里的司机可以理解成可以预知未来的司机,可以基于油箱无限大来囤油。
⚠️ 注意事项
  • 数据范围 : N = 10 5 N=10^5 N=105,总路程 × \times × 油价会轻易突破 2 × 10 9 2 \times 10^9 2×109,必须全线使用 long long
  • 数组大小 :在竞赛中,数组大小通常建议比题目给的上限多开 5 ∼ 10 5 \sim 10 5∼10 个位置,防止越界。

4. 易错点回顾 (My Mistakes)

  1. 初始化陷阱 :最初将 min_price 设为 0 0 0,导致 min(0, money[i]) 永远为 0 0 0(以为油是免费的)。纠正: 应初始化为第一站油价或一个极大值。
相关推荐
乐观勇敢坚强的老彭8 小时前
C++ 竞赛常用算法模板速查表
开发语言·c++·算法
我变成萤火虫8 小时前
河南萌新联赛2026第(三)场:郑州轻工业大学
数据结构·c++·算法·贪心算法·stl·深度优先·哈希算法
buhuizhiyuci9 小时前
【Linux 篇】数字世界的水流蓄水池 —— IO 缓冲区机制深度实战解析
linux·运维·服务器·c++
liulilittle9 小时前
LLM 推理引擎与内核系统工程原理
c++·ai·llm·内存·memory·core·kernel
啦啦啦啦啦zzzz9 小时前
moduo网络库 Acceptor TcpConnection
服务器·网络·c++·reactor·网络库
键盘会跳舞9 小时前
C++:右值引用与移动语义源码级深度拆解——现代C++性能优化的语言基石
c++·右值引用·移动语义
码匠许师傅9 小时前
【C++ 面试真题】聊聊 C++ 的虚函数和多态
java·c++·面试
lidtao10 小时前
青少年信息学奥赛C++四阶段学习路线(L1-L4完整体系)
c++·学习·软件工程·教培资源分享
djjjx.10 小时前
【 C++ 】多态
开发语言·c++·多态
鸿芯微控科技11 小时前
MFC关断后还有流量怎么办?零流量、阀门泄漏、压差与Python分析
c++·python·mfc·质量流量控制器·关断泄漏·零流量测试