1 条题解

  • 0
    @ 2025-10-23 22:36:59

    问题概述

    这是一个关于电动除雪机路径规划的问题。除雪机需要清理一条长度为 \ell 的道路,道路上有 nn 个充电站。除雪机每次充满电可以清理 kk 米道路,但充电站可能会损坏或修复。每天除雪机被随机放置在道路某个位置,需要计算清理整条道路的最短时间。

    算法思路

    1. 核心观察

    • 除雪机清理道路时需要往返充电站充电
    • 关键是最小化除雪过程中的空驶距离
    • 问题可以转化为分段处理动态规划

    2. 关键函数定义

    代码中定义了三个核心函数来计算不同情况下的清理成本:

    (1) cb(len) - 基本往返成本

    计算清理长度为 len 的道路所需的基本时间,考虑往返充电站的模式:

    int cb(int len) {
        int t = (len + k - 1) / k;  // 需要往返的次数
        return (len * t - (t - 1) * t / 2 * k) * 2;
    }
    

    (2) c1(len) - 单侧清理成本

    当道路长度 len <= k 时直接清理,否则分段处理:

    int c1(int len) {
        if (len <= k) return len;
        return cb((len - k) / 2) + cb((len - k + 1) / 2) + len;
    }
    

    (3) c2(len) - 双侧清理成本

    int c2(int len) {
        if (len <= k * 2) return len * 2;
        return cb((len - k * 2) / 2) + cb((len - k * 2 + 1) / 2) + len * 2;
    }
    

    (4) cm(len) - 最小清理成本

    寻找最优的分段方案:

    int cm(int len) {
        if (len <= k) return len;
        if (len <= k * 2) return len + len - k;
        
        int a = (len - k * 2) / 2, b = len - k * 2 - a;
        int ret = 1e18;
        // 尝试多种分段方案,找到最小值
        vector<int> can = {a, b, a / k * k, b / k * k, a / k * k + k, b / k * k + k};
        
        for (auto z : can) {
            for (int u = z - 2; u <= z + 2; u++) {
                if (u < 0 || u > len - 2 * k) continue;
                ret = min(ret, len + min(u, len - 2 * k - u) + k + cb(u) + cb(len - 2 * k - u));
            }
        }
        return ret;
    }
    

    3. 数据结构设计

    使用线段树维护区间信息,快速查询和更新:

    struct Info {
        int s1, s2, c1m2, c2m1;
        // s1: 单侧清理成本
        // s2: 双侧清理成本  
        // c1m2: 从左到右的特殊成本
        // c2m1: 从右到左的特殊成本
    };
    
    Info operator +(const Info &a, const Info &b) {
        return Info(
            a.s1 + b.s1,
            a.s2 + b.s2,
            min(a.c1m2 + b.s2, a.s1 + b.c1m2),
            min(a.c2m1 + b.s1, a.s2 + b.c2m1)
        );
    }
    

    4. 主要流程

    1. 初始化:读入充电站位置,建立线段树
    2. 处理每日查询
      • 更新可用的充电站集合(修复或损坏)
      • 找到除雪机位置两侧最近的可用充电站
      • 计算左右分段的最优解
    3. 输出结果:每天的最短清理时间

    5. 时间复杂度

    • 线段树构建:O(n)O(n)
    • 每次查询更新:O(logn)O(\log n)
    • 总体复杂度:O((n+q)logn)O((n + q) \log n),能够处理大规模数据

    算法标签

    • 线段树 (Segment Tree)
    • 动态规划 (Dynamic Programming)
    • 贪心算法 (Greedy Algorithm)
    • 区间查询 (Range Query)
    • 最优化问题 (Optimization Problem)

    解决思路的价值

    这种方法通过分段处理动态维护区间信息,有效地解决了带有充电约束的路径规划问题。线段树的使用使得能够快速响应充电站状态的动态变化,而精心设计的成本函数确保了清理时间的最优化。

    这个解决方案在时间复杂度空间复杂度之间取得了很好的平衡,能够处理题目中给出的最大数据规模(n,d250000n, d \leq 250000)。

    • 1

    信息

    ID
    3955
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者