题解:AtCoder AT_awc0080_b Quality Inspection and Product Disposal

【题目来源】

AtCoder:B - Quality Inspection and Product Disposal

【题目描述】

Takahashi is the quality control manager of a factory. The factory has a system where manufactured products are periodically inspected for quality, and products that do not meet the standards are disposed of.

The factory currently has \(N\) products, each numbered from \(1\) to \(N\). The quality score of product \(i\) is \(A_i\).

Takahashi performs \(Q\) quality inspections in order. In the \(j\)-th inspection \((1 \leq j \leq Q)\), a threshold value \(T_j\) is set, and among the products that have not yet been disposed of at that point, all products whose quality score is strictly less than \(T_j\) are disposed of. Once a product is disposed of, it is no longer subject to subsequent inspections. Note that the threshold value \(T_j\) is determined independently for each inspection, so it may be smaller than the previous threshold. In that case, if the relevant products have already been disposed of in previous inspections, no new products are disposed of.

Immediately after each inspection, the number of products newly disposed of in that inspection is recorded. For all \(Q\) quality inspections, determine the number of products newly disposed of in each inspection.

高桥是工厂的质量控制经理。工厂有一个系统,定期检查产品的质量,不符合标准的产品会被销毁。

工厂目前有 \(N\) 个产品,编号从 \(1\)\(N\)。产品 \(i\) 的质量得分为 \(A_i\)

高桥按顺序执行 \(Q\) 次质量检查。在第 \(j\) 次检查中(\(1 \leq j \leq Q\)),设定一个阈值 \(T_j\),并且在此时尚未销毁的产品中,所有质量得分严格小于 \(T_j\) 的产品将被销毁。一旦产品被销毁,它将不再受后续检查的影响。注意,每次检查的阈值 \(T_j\) 是独立确定的,因此它可能小于之前的阈值。在这种情况下,如果相关产品在之前的检查中已经被销毁,则不会再有新产品被销毁。

每次检查后,立即记录该次检查中新销毁的产品数量。对于所有 \(Q\) 次质量检查,确定每次检查中新销毁的产品数量。

【输入】

\(N\) \(Q\)
\(A_1\) \(A_2\) \(\ldots\) \(A_N\)
\(T_1\)
\(T_2\)
\(\vdots\)
\(T_Q\)

  • The first line contains an integer \(N\) representing the number of products and an integer \(Q\) representing the number of quality inspections, separated by a space.
  • The second line contains integers \(A_1, A_2, \ldots, A_N\) representing the quality scores of each product, separated by spaces.
  • In the following \(Q\) lines, the \(j\)-th line \((1 \leq j \leq Q)\) contains an integer \(T_j\) representing the threshold value for the \(j\)-th inspection.

【输出】

Output \(Q\) lines. The \(j\)-th line \((1 \leq j \leq Q)\) should contain the number of products newly disposed of in the \(j\)-th inspection.

【输入样例】

5 3
3 1 4 1 5
2
4
3

【输出样例】

2
1
0

【核心思想】

  1. 问题分析:给定 \(N\) 个产品的质量分数 \(A_1, A_2, \ldots, A_N\),进行 \(Q\) 次检查,每次检查设定阈值 \(T_j\),销毁所有尚未被销毁且质量分数严格小于 \(T_j\) 的产品。需要记录每次检查新销毁的产品数量。由于每次只销毁比之前阈值更小的产品,且已销毁的产品不再参与后续检查,这是一个排序 + 双指针/二分查找问题。

  2. 算法选择

    • 排序预处理:将质量分数数组 \(A\) 升序排序,便于二分查找
    • 二分查找(upper_bound):快速找到小于 \(T_j\) 的元素个数
    • 指针维护:用变量 \(st\) 记录当前已处理到的位置,避免重复计算
  3. 关键步骤

    • 排序:将数组 \(A\) 升序排序,时间 \(O(N \log N)\)
    • 初始化指针\(st = 1\),表示当前从第 \(1\) 个元素开始处理
    • 处理每个查询 \(T_j\)
      • 使用 upper_bound(a+1, a+n+1, T_j-1) 找到第一个 \(> T_j-1\) 的位置 \(pos\)
      • 等价于找到第一个 \(\geq T_j\) 的位置,即质量分数 \(< T_j\) 的元素个数为 \(pos - 1\)
      • 判断新销毁数量
        • \(pos \leq st\):说明所有 \(< T_j\) 的产品已被销毁,新销毁数量为 \(0\)
        • \(pos > st\):新销毁数量为 \(pos - st\)(区间 \([st, pos-1]\) 内的元素)
      • 更新指针\(st = \max(st, pos)\),将 \(st\) 移动到已处理的最远位置
    • 输出每次查询的新销毁数量
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N \log N + Q \log N)\),排序 \(O(N \log N)\),每次查询二分 \(O(\log N)\)
    • 空间复杂度:\(O(N)\),存储质量分数数组
  5. 排序与二分查找的核心思想

    • 有序化预处理:将无序数据排序后,可以利用二分查找快速定位
    • upper_bound技巧:查找第一个 \(> x\) 的元素位置,等价于统计 \(\leq x\) 的元素个数
    • 指针维护:用 \(st\) 记录已处理位置,避免重复统计已销毁产品,实现 \(O(1)\) 的区间长度计算
    • 离线处理:先排序再处理查询,将动态问题转化为静态问题
    • 适用于区间统计、动态删除、批量查询等场景

【算法标签】

整数二分

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int n, q, st;  // n: 数组长度,q: 查询次数,st: 起始位置
int a[N];  // 存储数组
int main()
{
    cin >> n >> q;  // 输入数组长度和查询次数
    for (int i = 1; i <= n; i++)  // 输入数组元素
        cin >> a[i];
    sort(a + 1, a + n + 1);  // 对数组进行升序排序
    st = 1;  // 初始化起始位置为1
    while (q--)  // 处理每个查询
    {
        int t;  // 查询值
        cin >> t;  // 输入查询值
        int pos = upper_bound(a + 1, a + n + 1, t - 1) - a;  // 找到第一个大于t-1的位置
        if (pos <= st)  // 如果位置小于等于起始位置
            cout << 0 << endl;  // 输出0
        else
            cout << pos - st << endl;  // 输出区间长度
        st = max(st, pos);  // 更新起始位置
    }
    return 0;
}

【运行结果】

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