题解:AtCoder AT_awc0031_d Library Inventory Check

【题目来源】

AtCoder:D - Library Inventory Check

【题目描述】

Takahashi is working as a librarian and is in charge of a book inspection spanning \(N\) days.
高桥是一名图书馆员,负责一项为期 \(N\) 天的书籍检查工作。

This library has \(M\) books. To ensure that no deterioration or damage to books is overlooked, a standard has been established that each book \(j\) \((1 \leq j \leq M)\) must be inspected on at least \(R_j\) days out of the \(N\) days.
这个图书馆有 \(M\) 本书。为了确保不遗漏书籍的劣化或损坏,制定了一个标准:每本书 \(j\)\(1 \leq j \leq M\))在 \(N\) 天中至少需要被检查 \(R_j\) 天。

On the other hand, the maximum number of books that can be inspected on day \(i\) \((1 \leq i \leq N)\) is \(L_i\). Also, the same book cannot be inspected multiple times on the same day, but the same book can be inspected again on a different day.
另一方面,每天 \(i\)\(1 \leq i \leq N\))最多可以检查 \(L_i\) 本书。此外,同一本书在同一天不能被检查多次,但同一本书可以在不同日期再次检查。

Takahashi is free to decide which books to inspect on which days. Determine whether it is possible to create an inspection plan that satisfies the inspection requirements for all books.
高桥可以自由决定在哪天检查哪些书。判断是否有可能制定一个满足所有书籍检查要求的检查计划。

Specifically, determine whether there exists an inspection plan that satisfies all of the following conditions:
具体来说,判断是否存在一个满足以下所有条件的检查计划:

  • The number of books inspected on each day \(i\) is at most \(L_i\).
    每天 \(i\) 检查的书籍数量不超过 \(L_i\)
  • The same book is not inspected more than once on the same day.
    同一本书在同一天不被检查超过一次。
  • The total number of days each book \(j\) is inspected is at least \(R_j\).
    每本书 \(j\) 被检查的总天数至少为 \(R_j\)

【输入】

\(N\) \(M\)
\(L_1\) \(L_2\) \(\ldots\) \(L_N\)
\(R_1\) \(R_2\) \(\ldots\) \(R_M\)

  • The first line contains \(N\), the number of days in the inspection period, and \(M\), the number of books, separated by a space.
  • The second line contains \(L_1, L_2, \ldots, L_N\), the maximum number of books that can be inspected on each day, separated by spaces.
  • The third line contains \(R_1, R_2, \ldots, R_M\), the required number of inspection days for each book, separated by spaces.

【输出】

If an inspection plan that satisfies the inspection requirements for all books exists, print Yes; otherwise, print No on a single line.

【输入样例】

3 4
2 3 2
1 2 1 2

【输出样例】

Yes

【核心思想】

  1. 问题分析:给定 \(N\) 天和 \(M\) 本书,每天 \(i\) 最多检查 \(L_i\) 本书,每本书 \(j\) 至少需要被检查 \(R_j\) 天。需要判断是否存在一个检查计划满足所有约束。这是一个贪心 + 排序 + 二分问题,关键在于将问题转化为"老师需求学生能力"的匹配模型。

  2. 算法选择

    • 问题转化:将天数看作"学生"(每天能提供 \(L_i\) 的能力),书籍看作"老师"(每本书需要 \(R_j\) 的要求)
    • 排序策略:将 \(L\) 数组升序排序,\(R\) 数组降序排序
    • 贪心判定:优先满足要求高的书籍(老师),检查能力达标的天数(学生)是否足够
    • 二分查找:使用 lower_bound 快速找到能力值 \(\geq i\) 的天数位置
  3. 关键步骤

    • 读取输入\(N\)(天数)、\(M\)(书籍数量)、\(L[1..N]\)(每天最大检查数)、\(R[1..M]\)(每本书最少检查天数)
    • 排序
      • sort(l + 1, l + n + 1):将 \(L\) 升序排序
      • sort(r + 1, r + m + 1, greater<int>()):将 \(R\) 降序排序
    • 贪心判定(遍历每本书 \(i\)\(1\)\(M\)):
      • 累加需求sumr += r[i](累加前 \(i\) 本书的总需求)
      • 二分查找pos = lower_bound(l + 1, l + n + 1, i) - l(找到第一个 \(L \geq i\) 的位置)
      • 计算能力suml += (n - (pos - 1))(累加能力值 \(\geq i\) 的天数总和)
      • 判定:如果 suml < sumr,说明无法满足,输出 No
    • 输出结果:如果所有书籍都能满足,输出 Yes
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N \log N + M \log M + M \log N)\),排序 \(O(N \log N + M \log M)\),每次二分 \(O(\log N)\)
    • 空间复杂度:\(O(N + M)\),存储 \(L\)\(R\) 数组
  5. 贪心 + 排序 + 二分的核心思想

    • 问题转化技巧:将复杂的调度问题转化为经典的"老师-学生"能力匹配问题
    • 排序贪心策略:优先处理要求高的书籍(降序),确保最难满足的需求先被考虑
    • 前缀和累加:用 sumlsumr 分别累加能力和需求,避免重复计算
    • 二分优化:利用 lower_bound\(O(\log N)\) 时间内找到分界点,快速统计达标天数
    • 正确性证明:如果前 \(i\) 本要求最高的书都无法满足,则整体无解;反之则存在解

【解题思路】

【算法标签】

贪心

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;

int n, m;
int l[N], r[N];  // l: 学生数组, r: 老师数组

signed main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> l[i];
    }
    for (int i = 1; i <= m; i++)
    {
        cin >> r[i];
    }

    sort(l + 1, l + n + 1);  // 对学生能力排序
    sort(r + 1, r + m + 1, greater<int>());  // 对老师要求降序排序

    int suml = 0, sumr = 0;  // suml: 学生总能力, sumr: 老师总要求

    for (int i = 1; i <= m; i++)  // 遍历老师
    {
        sumr += r[i];  // 累加老师要求

        // 查找第一个能力 >= i 的学生位置
        int pos = lower_bound(l + 1, l + n + 1, i) - l;
        // 能力 >= i 的学生数量
        suml += (n - (pos - 1));

        // 如果当前学生的总能力小于老师总要求
        if (suml < sumr)
        {
            cout << "No" << endl;
            return 0;
        }
    }
    cout << "Yes" << endl;
    return 0;
}

【运行结果】

3 4
2 3 2
1 2 1 2
Yes
posted @ 2026-06-14 10:42  团爸讲算法  阅读(5)  评论(0)    收藏  举报