题解:#9210.[DAY02]武器排队 审核通过

root 站长 2025-10-06 19:11:17 3

题目本身没什么题意难度,很好懂。也没什么算法难度,一看就知道是个排序和二分。但是写了就会发现是真难写。

子任务 1

只有一种类型 A,不用管类型了。直接按攻击力从小到排序。

  1. 如果 ,显然就是输出 lower_bound 的位置。
  2. 如果 ,显然要么第一个小于等于 ,要么全都不小于,所以输出必然是

子任务 2

保证都是找第一个大于等于的位置。类型 AC 就是子任务 1 的第一种情况。类型 B 就是子任务 1 的 第二种情况。

子任务 3

做法 1

如果按照三个武器类型 两种 类型,写 种情况的二分,那一不小心你就要写 行。当然 Gemini 就是这么写的,Gemini 的代码会放在题解最后。

做法 2

显然整体在抽象意义下也是有序的。而二分的核心无非就是:

  1. mid 满足条件时更新答案。
  2. 如果需要去 mid 左边找更优答案就 r = mid - 1;
  3. 如果需要去 mid 右边找更优答案就 l = mid + 1;

一般的二分我们会把 1 融入到 2,3 之一。这题我们拆开来就会非常好写了。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100000;
int n;
pair<char, int> a[MAXN + 5];
bool cmp(pair<char, int> x, pair<char, int> y)
{
    if (x.first != y.first)
        return x.first < y.first;
    if (x.first == 'B')
        return x.second > y.second;
    return x.second < y.second;
}
// 当前符合要求
bool ok(char op, int x, char midOp, int midX)
{
    // op == midOp 可以分配率一下,但是我想对齐,交给编译器优化
    if (op == midOp && x >= 0 && midX >= x ||
        op == midOp && x < 0 && midX <= -x)
        return true;
    return false;
}
// 需要去左边找更优解
bool lft(char op, int x, char midOp, int midX)
{
    if (op != midOp)
        return op < midOp;
    if (op == 'A' || op == 'C')
    {
        // 升序
        if (x >= 0) // 找第一个大于等于 x 的
            return midX >= x;
        else // 找第一个小于等于 -x 的
            return true;
    }
    // 降序
    if (x >= 0) // 找第一个大于等于 x 的
        return true;
    else // 找第一个小于等于 -x 的
        return midX <= -x;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i].first >> a[i].second;
    sort(a + 1, a + n + 1, cmp);
    /*
    for (int i = 1; i <= n; i++)
        cout << a[i].first << " ";
    cout << "\n";
    for (int i = 1; i <= n; i++)
        cout << a[i].second << " ";
    cout << "\n";
    */
    int Q;
    cin >> Q;
    while (Q--)
    {
        char op;
        int x;
        cin >> op >> x;
        int l = 1;
        int r = n;
        int ans = 0;
        while (l <= r)
        {
            int mid = (l + r) / 2;
            char midOp = a[mid].first;
            int midX = a[mid].second;
            if (ok(op, x, midOp, midX)) // 当前符合要求
                ans = mid;
            if (lft(op, x, midOp, midX)) // 需要去左边找更优解
                r = mid - 1;
            else
                l = mid + 1;
        }
        cout << ans << "\n";
    }
    return 0;
}

[Copy](javascript:;)

Gemini 的 100+ 行代码

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>

// 主函数包含解题逻辑
void solve() {
    // 使用快速 I/O
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    int n;
    std::cin >> n;

    // 分别用 vector 存储三类武器的攻击力
    std::vector<int> a_weapons;
    std::vector<int> b_weapons;
    std::vector<int> c_weapons;

    // 读取 n 把武器并按类型分组
    for (int i = 0; i < n; ++i) {
        char type;
        int attack;
        std::cin >> type >> attack;
        if (type == 'A') {
            a_weapons.push_back(attack);
        } else if (type == 'B') {
            b_weapons.push_back(attack);
        } else { // type == 'C'
            c_weapons.push_back(attack);
        }
    }

    // 按照题目要求对各类武器进行排序
    // 类型 A (近战): 攻击力从小到大
    std::sort(a_weapons.begin(), a_weapons.end());
    // 类型 B (射手): 攻击力从大到小
    std::sort(b_weapons.begin(), b_weapons.end(), std::greater<int>());
    // 类型 C (法师): 攻击力从小到大
    std::sort(c_weapons.begin(), c_weapons.end());

    int q;
    std::cin >> q;

    // 计算 B 和 C 类武器在最终排序列表中的起始位置(偏移量)
    size_t a_size = a_weapons.size();
    size_t b_offset = a_size;
    size_t c_offset = a_size + b_weapons.size();

    // 处理 Q 次查询
    for (int i = 0; i < q; ++i) {
        char type;
        int x;
        std::cin >> type >> x;

        if (type == 'A') {
            if (x >= 0) {
                // 查找攻击力 >= x 的第一把武器
                // lower_bound 返回第一个不小于 x 的元素的迭代器
                auto it = std::lower_bound(a_weapons.begin(), a_weapons.end(), x);
                if (it == a_weapons.end()) {
                    std::cout << 0 << "\n";
                } else {
                    // 位置是 1-based 的,等于 0-based 的下标 + 1
                    std::cout << (it - a_weapons.begin()) + 1 << "\n";
                }
            } else {
                // 查找攻击力 <= -x 的第一把武器
                long long target = -x;
                // A 升序排列,第一把武器攻击力最低。
                // 如果它满足条件,那么它就是位置最靠前的答案。
                if (a_weapons.empty() || a_weapons[0] > target) {
                    std::cout << 0 << "\n";
                } else {
                    std::cout << 1 << "\n";
                }
            }
        } else if (type == 'B') {
            if (x >= 0) {
                // 查找攻击力 >= x 的第一把武器
                // B 降序排列,第一把武器攻击力最高。
                // 如果它满足条件,那么它就是位置最靠前的答案。
                if (b_weapons.empty() || b_weapons[0] < x) {
                    std::cout << 0 << "\n";
                } else {
                    std::cout << b_offset + 1 << "\n";
                }
            } else {
                // 查找攻击力 <= -x 的第一把武器
                long long target = -x;
                // B 降序排列,用 lower_bound 和 std::greater 查找第一个 e <= target 的元素。
                auto it = std::lower_bound(b_weapons.begin(), b_weapons.end(), target, std::greater<int>());
                if (it == b_weapons.end()) {
                    std::cout << 0 << "\n";
                } else {
                    std::cout << b_offset + (it - b_weapons.begin()) + 1 << "\n";
                }
            }
        } else { // type == 'C'
            if (x >= 0) {
                // 查找攻击力 >= x 的第一把武器
                auto it = std::lower_bound(c_weapons.begin(), c_weapons.end(), x);
                if (it == c_weapons.end()) {
                    std::cout << 0 << "\n";
                } else {
                    std::cout << c_offset + (it - c_weapons.begin()) + 1 << "\n";
                }
            } else {
                // 查找攻击力 <= -x 的第一把武器
                long long target = -x;
                // C 升序排列,逻辑同 A。
                if (c_weapons.empty() || c_weapons[0] > target) {
                    std::cout << 0 << "\n";
                } else {
                    std::cout << c_offset + 1 << "\n";
                }
            }
        }
    }
}

int main() {
    solve();
    return 0;
}

[Copy](javascript:;)

{{ vote && vote.total.up }}