283树苗健康提升策略 中等 | 豆包MarsCode AI刷题

9 阅读5分钟

提醒,这道题的评测目前是错误的。我只是按照我的思路写一篇题解。

题意

小U在农场的一片林地上种植了N棵树苗,每棵树苗都有一个初始健康度值。小U希望通过浇水的方式使所有树苗的健康度达到或超过目标值M。 每次浇水,小U可以选择任意一棵树苗,该树苗的健康度会增加A点,其他所有树苗的健康度也会间接增加B点。为了节省资源,小U需要找出使所有树苗的健康度达到目标值的最少浇水次数。 例如,小U的农场有4棵树苗,初始健康度为{2, 3, 6, 8},目标是使所有树苗的健康度至少达到10。小U可以选择最优的浇水方式,使得仅需要浇水2次即可完成目标。 要解决这个问题,我们需要找到使所有树苗的健康度达到或超过目标值 MMM 的最少浇水次数 TTT。每次浇水时,我们可以选择任意一棵树苗,被选中的树苗健康度增加 AAA,其他树苗的健康度增加 BBB。需要注意的是,AAA 可能小于 BBB。

思路分析:

我们需要找到最小的 TTT,使得对于每棵树苗,其最终的健康度满足:

hi+xi×A+(T−xi)×B≥Mh_i + x_i \times A + (T - x_i) \times B \geq Mhi​+xi​×A+(T−xi​)×B≥M

其中:

  • hih_ihi​ 是第 iii 棵树苗的初始健康度。
  • xix_ixi​ 是第 iii 棵树苗被直接浇水的次数(即被选中的次数)。
  • TTT 是总的浇水次数,满足 T=∑i=1NxiT = \sum_{i=1}^{N} x_iT=∑i=1N​xi​。

为了解决这个问题,我们可以将其转化为一个整数规划问题,并通过二分搜索来找到最小的 TTT。

算法步骤:

  1. 确定浇水次数的上下界:

    • 下界 TlowT_{\text{low}}Tlow​:可以从 000 开始。
    • 上界 ThighT_{\text{high}}Thigh​:可以设置为一个足够大的值,例如 Thigh=M×Nmin⁡(A,B)T_{\text{high}} = \frac{M \times N}{\min(A, B)}Thigh​=min(A,B)M×N​。
  2. 二分搜索最小的 TTT:

    • 在 TlowT_{\text{low}}Tlow​ 和 ThighT_{\text{high}}Thigh​ 之间进行二分搜索。
    • 对于每个中间值 TmidT_{\text{mid}}Tmid​,检查是否存在一组 xix_ixi​ 满足条件。
  3. 检查可行性:

    • 对于每棵树苗,根据以下公式计算 xix_ixi​ 的取值范围:

      • 当 A−B≥0A - B \geq 0A−B≥0(即 A≥BA \geq BA≥B)时:

        xi≥⌈M−hi−Tmid×BA−B⌉x_i \geq \left\lceil \frac{M - h_i - T_{\text{mid}} \times B}{A - B} \right\rceilxi​≥⌈A−BM−hi​−Tmid​×B​⌉

      • 当 A−B<0A - B < 0A−B<0(即 A<BA < BA<B)时:

        xi≤⌊hi+Tmid×B−MB−A⌋x_i \leq \left\lfloor \frac{h_i + T_{\text{mid}} \times B - M}{B - A} \right\rfloorxi​≤⌊B−Ahi​+Tmid​×B−M​⌋

    • 确保 xix_ixi​ 在 000 到 TmidT_{\text{mid}}Tmid​ 之间,且满足 xix_ixi​ 的取值范围。

    • 检查是否存在一组整数 xix_ixi​ 满足 ∑i=1Nxi=Tmid\sum_{i=1}^{N} x_i = T_{\text{mid}}∑i=1N​xi​=Tmid​。

  4. 更新搜索范围:

    • 如果在 TmidT_{\text{mid}}Tmid​ 下有可行解,则更新上界 Thigh=TmidT_{\text{high}} = T_{\text{mid}}Thigh​=Tmid​。
    • 否则,更新下界 Tlow=Tmid+1T_{\text{low}} = T_{\text{mid}} + 1Tlow​=Tmid​+1。
  5. 终止条件:

    • 当 Tlow≥ThighT_{\text{low}} \geq T_{\text{high}}Tlow​≥Thigh​ 时,最小的 TTT 就是 TlowT_{\text{low}}Tlow​。

示例代码实现:

下面是上述算法的 Python 实现:

python
复制代码
def min_watering_times(N, M, A, B, health):
    def is_feasible(T):
        x_min_sum = 0  # 对于 A >= B 的情况
        x_max_sum = 0  # 对于 A < B 的情况
        if A == B:
            for h in health:
                if h + T * B < M:
                    return False
            return True
        elif A > B:
            for h in health:
                x_i_min = max(0, -(-(M - h - T * B) // (A - B)))  # 上取整
                if x_i_min > T:
                    return False
                x_min_sum += x_i_min
            return x_min_sum <= T
        else:
            for h in health:
                x_i_max = max(0, (h + T * B - M) // (B - A))  # 下取整
                if x_i_max < 0 or x_i_max > T:
                    x_i_max = min(T, max(0, x_i_max))
                x_max_sum += x_i_max
            return x_max_sum >= T
    # 二分搜索
    left, right = 0, max((M - min(health)) // min(A, B) * N, 1)
    result = -1
    while left <= right:
        mid = (left + right) // 2
        if is_feasible(mid):
            result = mid
            right = mid - 1
        else:
            left = mid + 1
    return result

# 示例输入
N = 4
M = 10
A = 3  # 假设 A = 3
B = 2  # 假设 B = 2
health = [2, 3, 6, 8]

print("最少浇水次数为:", min_watering_times(N, M, A, B, health))

注意事项:

  • 关于 A 和 B: 由于 AAA 和 BBB 是题目给定的参数,具体数值需要根据实际情况输入。在上述代码中,我们假设 A=3A = 3A=3,B=2B = 2B=2。
  • 整数处理: 在计算 xix_ixi​ 的取值范围时,需要注意向上取整和向下取整的操作,以确保 xix_ixi​ 为整数。
  • 边界条件: 如果 A=BA = BA=B,那么每棵树苗的健康度都会以相同的速率增加,此时只需要计算达到目标所需的最小浇水次数。

算法复杂度:

  • 时间复杂度: 二分搜索的次数为 O(log⁡Tmax)O(\log T_{\text{max}})O(logTmax​),每次检查的时间为 O(N)O(N)O(N),因此总的时间复杂度为 O(Nlog⁡Tmax)O(N \log T_{\text{max}})O(NlogTmax​)。
  • 空间复杂度: O(1)O(1)O(1),只需要常数级别的额外空间。

总结:

通过将问题转化为整数规划,并使用二分搜索的方法,我们可以高效地找到使所有树苗的健康度达到目标值所需的最少浇水次数。该算法考虑了 AAA 和 BBB 之间的关系,适用于 A≥BA \geq BA≥B 和 A<BA < BA<B 的情况。