最优河堤加固(二分答案 + 前缀和)

题目描述

给定各段河堤高度 heights[i],预算 MaxCosts,每车最大载量 MaxCapacity,每车运输成本 TransportationCostPerShipment,每单位土填埋成本 UnitCost。求在预算内能使所有河堤最低高度的最大值达到多少(可以超过原最大高度)。

输入描述

依次输入预算、车载量、运输成本、单位填埋成本、河堤数、高度数组。

输出描述

加固后的最大最低高度。

示例

输入:

text

复制代码
100 10 5 2 5
1 2 5 3 4

输出:

text

复制代码
11

解题思路

排序高度并求前缀和。二分目标高度 H,计算所需土量:找到第一个高度 ≥ H 的位置 k(lower_bound),所需土量为 H*k - prefix[k]。总成本 = 土量×填埋成本 + ceil(土量/载量)×运输成本。若 ≤ 预算则可行,向右收缩;否则向左。二分用上取整防止死循环。

C 语言代码

c

复制代码
#include <stdio.h>
#include <stdlib.h>

int cmp_ll(const void *a, const void *b) {
    long long x = *(const long long *)a, y = *(const long long *)b;
    return (x > y) - (x < y);
}

int main(void) {
    long long MaxCosts, MaxCapacity, TransCost, UnitCost;
    int n;
    if (scanf("%lld %lld %lld %lld %d", &MaxCosts, &MaxCapacity,
              &TransCost, &UnitCost, &n) != 5) return 0;

    long long *h = (long long *)malloc(sizeof(long long) * n);
    for (int i = 0; i < n; i++) scanf("%lld", &h[i]);

    qsort(h, n, sizeof(long long), cmp_ll);

    /* 前缀和 prefix[i] = h[0..i-1] 之和,prefix[0]=0 */
    long long *prefix = (long long *)malloc(sizeof(long long) * (n + 1));
    prefix[0] = 0;
    for (int i = 0; i < n; i++) prefix[i + 1] = prefix[i] + h[i];

    /* 二分上界:把全部填到 max + 预算/单位成本 即可 */
    long long lo = h[0], hi = h[n - 1] + MaxCosts / (UnitCost > 0 ? UnitCost : 1) + 1;

    while (lo < hi) {
        long long mid = lo + (hi - lo + 1) / 2; /* 上取整,避免死循环 */

        /* 找第一个 >= mid 的位置 k(lower_bound) */
        int l = 0, r = n; /* [l, r) */
        while (l < r) {
            int m2 = (l + r) / 2;
            if (h[m2] >= mid) r = m2;
            else l = m2 + 1;
        }
        int k = l;

        /* 需要填埋的土量:mid*k - prefix[k] */
        long long soil = mid * (long long)k - prefix[k];

        /* 运输车数:ceil(soil / MaxCapacity) */
        long long cars = (soil + MaxCapacity - 1) / MaxCapacity;

        long long cost = soil * UnitCost + cars * TransCost;

        if (cost <= MaxCosts) lo = mid;   /* 可行,尝试更高 */
        else hi = mid - 1;                /* 不可行,降低 */
    }

    printf("%lld\n", lo);

    free(h); free(prefix);
    return 0;
}
相关推荐
Dream it possible!4 分钟前
LeetCode 面试经典 150_多维动态规划_交错字符串(97_C++_中等)
算法·leetcode·面试·动态规划
心抵鹊29 分钟前
算法之双指针系列(一)
算法·leetcode
十二38 分钟前
【洛谷题解】P1083 [NOIP 2012 提高组] 借教室(二分答案 + 差分)
数据结构·c++·算法·蓝桥杯
小此方2 小时前
[算法实战论:动态规划]回文串问题的dp解法,回文串问题的母题,以及以此为基础的派生题
算法·动态规划
Pniubi2 小时前
力扣560.和为k的子数组
算法·leetcode·职场和发展
D e re k ZH3 小时前
C++ 从零入门(一):基础语法与程序结构
数据结构·c++·算法
Pniubi3 小时前
力扣438.找到字符串中所有字母异位词
算法·leetcode·职场和发展
東隅已逝,桑榆非晚6 小时前
算法6. 双指针法-查找总价格为目标的两个商品
c++·学习·算法
Eyfcom6 小时前
〖物联网终端实战 01〗UWB 室内高精度定位:仓储 AGV 与人员的厘米级轨迹追踪
物联网·算法·物流系统·快递系统·跨境物流快递系统·物联网终端实战
bro_Java6667 小时前
《排序的底层逻辑:比较、交换与分治》
java·算法·排序算法