返回

Codeforces Round #664 (Div. 1) A. Boboniu Chats with Du 题解

见解分享

作为一道经典的 Codeforces 签到题,A. Boboniu Chats with Du 考察了枚举和贪心策略在解决问题中的巧妙运用。这道题让我们回想起数学中的一个基本原理:最小化损失

背景

想象一下 Boboniu 和 Du 的精彩对话。Boboniu 有一个聊天记录,其中包含一系列聊天消息。每个消息都有一个权重,表示该消息的“调皮程度”。Du 对调皮消息十分敏感,一旦累积调皮值超过某个阈值 m,他就会禁言 Boboniu。

策略

我们的目标是帮助 Boboniu 最大程度地调皮,同时避免被禁言。为此,我们需要采取以下策略:

  1. 枚举 b 的数量: 首先,我们枚举使用多少条“会被禁言”的消息(称为 b)。
  2. 计算禁言天数: 对于每一种 b 的数量,我们计算 b 带来的禁言天数(b 的权重之和)。
  3. 覆盖所有不想选的消息: 如果禁言天数不足以覆盖所有我们不想选择的“会被禁言”的消息,则跳过此枚举。
  4. 最小化 b 的数量: 在满足覆盖条件的前提下,我们希望使用尽可能少的 b。
  5. 计算 a 的数量: 一旦确定了 b 的数量,我们就可以计算出“不会被禁言”的消息(称为 a)的数量。a 的数量等于我们想说的所有调皮话的权重之和与 m 之差。

优化

为了提高效率,我们加入了两个优化:

  1. 跳过枚举: 如果选取的 b 太少,导致禁言天数不够,则直接跳过该枚举。
  2. 减少 b 的数量: 如果选取的 b 太多,我们尝试减少 b 的数量,同时保证覆盖条件。

实现

我们可以使用 Python 代码轻松实现此策略:

def solve(weights, m):
    # 初始化
    n = len(weights)
    weights.sort()
    max_b = 0

    # 枚举 b 的数量
    for i in range(n):
        b = i + 1
        total_ban_time = sum(weights[:b])

        # 跳过枚举
        if total_ban_time < m:
            continue

        # 减少 b 的数量
        while total_ban_time > m and b > 0:
            b -= 1
            total_ban_time -= weights[b]

        # 计算 a 的数量
        a = max(0, sum(weights[b:]) - m)

        # 更新最大 b 的数量
        if a > 0:
            max_b = max(max_b, b)

    return max_b

复杂度分析

此算法的时间复杂度为 O(n log n),其中 n 是消息的数量。它需要对消息按权重进行排序,然后枚举 b 的数量。

总结

A. Boboniu Chats with Du 题解展示了枚举和贪心策略相结合的强大力量。通过最小化 b 的数量并覆盖所有不需要的消息,我们可以帮助 Boboniu 最大程度地调皮,同时避免被禁言。