AtCoder Weekday Contest 0032 Beta题解(AWC 0032 Beta A-E)

A - Closeness of Fireworks

【题目来源】

AtCoder:A - Closeness of Fireworks

【题目描述】

On the night of a summer festival, Takahashi and Aoki are watching fireworks from different locations. During the fireworks show, \(N\) fireworks are launched.
在一个夏季节日的夜晚,高桥和青木在不同的地点观看烟花。在烟花表演期间,共发射了 \(N\) 枚烟花。

At the moment the \(i\)-th firework bursts, Takahashi is at coordinates \((X_i, Y_i)\) and Aoki is at coordinates \((P_i, Q_i)\) on a two-dimensional plane. Their positions may differ for each firework.
\(i\) 枚烟花绽放的瞬间,高桥位于二维平面上的坐标 \((X_i, Y_i)\),青木位于坐标 \((P_i, Q_i)\)。他们的位置可能因烟花而异。

When the Euclidean distance between Takahashi and Aoki at the moment a firework bursts is at most \(R\), we say they "watched it together." Here, the Euclidean distance between the two for the \(i\)-th firework is \(\sqrt{(X_i - P_i)^2 + (Y_i - Q_i)^2}\).
当烟花绽放瞬间高桥和青木之间的欧几里得距离不超过 \(R\) 时,我们说他们"一起观看了"该烟花。这里,第 \(i\) 枚烟花时两人之间的欧几里得距离为 \(\sqrt{(X_i - P_i)^2 + (Y_i - Q_i)^2}\)

Among the \(N\) fireworks, find the number of fireworks that the two watched together.
\(N\) 枚烟花中,求两人一起观看的烟花数量。

【输入】

\(N\) \(R\)
\(X_1\) \(Y_1\) \(P_1\) \(Q_1\)
\(X_2\) \(Y_2\) \(P_2\) \(Q_2\)
\(\vdots\)
\(X_N\) \(Y_N\) \(P_N\) \(Q_N\)

  • The first line contains the number of fireworks \(N\) and the distance threshold \(R\) for determining whether they watched together, separated by a space.
  • The \((1 + i)\)-th line \((1 \leq i \leq N)\) contains Takahashi's coordinates \((X_i, Y_i)\) and Aoki's coordinates \((P_i, Q_i)\) at the moment the \(i\)-th firework bursts, separated by spaces.

【输出】

Print the number of fireworks the two watched together in one line.

【输入样例】

3 5
0 0 3 4
0 0 6 0
1 1 1 1

【输出样例】

2

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, r, cnt;  // n: 点数, r: 距离阈值, cnt: 计数

signed main()
{
    cin >> n >> r;  // 输入点数和距离阈值
    for (int i = 1; i <= n; i++)  // 处理每个点
    {
        int x, y, p, q;  // (x,y)是点坐标, (p,q)是参考点坐标
        cin >> x >> y >> p >> q;
        if ((x - p) * (x - p) + (y - q) * (y - q) <= r * r)  // 距离平方≤r²
        {
            cnt++;  // 满足条件,计数加1
        }
    }
    cout << cnt << endl;  // 输出结果
    return 0;
}

【运行结果】

3 5
0 0 3 4
0 0 6 0
1 1 1 1
2

B - Package Delivery Schedule

【题目来源】

AtCoder:B - Package Delivery Schedule

【题目描述】

Takahashi is a staff member working at a delivery center. The delivery center has \(N\) destinations, each numbered from \(1\) to \(N\). He needs to deliver \(A_i\) packages to destination \(i\).
高桥是配送中心的一名工作人员。该配送中心有 \(N\) 个目的地,编号从 \(1\)\(N\)。他需要向目的地 \(i\) 配送 \(A_i\) 个包裹。

Takahashi can visit only one destination per day and deliver at most \(K\) packages to that destination. If there are packages that cannot be delivered in a single day, he visits the same destination again on another day to deliver them. Therefore, completing the delivery to destination \(i\) takes \(\lceil A_i / K \rceil\) days, and the total number of days required to complete deliveries to all destinations is \(\sum_{i=1}^{N} \lceil A_i / K \rceil\) days.
高桥每天只能访问一个目的地,并且最多可向该目的地配送 \(K\) 个包裹。如果有包裹无法在一天内送完,他会在另一天再次访问同一目的地进行配送。因此,完成对目的地 \(i\) 的配送需要 \(\lceil A_i / K \rceil\) 天,完成所有目的地的配送所需的总天数为 \(\sum_{i=1}^{N} \lceil A_i / K \rceil\) 天。

Aoki is the manager of the delivery center and wants to reduce the number of delivery days as much as possible. To this end, Aoki is considering increasing the daily delivery capacity before deliveries begin. Specifically, Aoki can choose an integer \(x\) with \(0 \leq x \leq M\) and change the daily delivery capacity from \(K\) to \(K + x\). This change is made only once before deliveries start and cannot be altered during the delivery process. Note that choosing \(x = 0\), i.e., not changing the capacity, is also allowed.
青木是配送中心的经理,希望尽可能减少配送天数。为此,青木考虑在配送开始前提高每日配送能力。具体来说,青木可以选择一个满足 \(0 \leq x \leq M\) 的整数 \(x\),将每日配送能力从 \(K\) 改为 \(K + x\)。此更改仅在配送开始前进行一次,且在配送过程中不可更改。注意,选择 \(x = 0\),即不更改配送能力,也是允许的。

Find the minimum number of days required for Takahashi to complete all deliveries when Aoki chooses \(x\) optimally.
当青木最优地选择 \(x\) 时,求高桥完成所有配送所需的最小天数。

In other words, for an integer \(x\) satisfying \(0 \le x \le M\), the total number of delivery days is
换句话说,对于一个满足 \(0 \le x \le M\) 的整数 \(x\),总配送天数为

\(\sum_{i=1}^{N} \left\lceil \frac{A_i}{K + x} \right\rceil\)

Output the total number of delivery days when \(x\) is chosen to minimize this value.
输出当 \(x\) 被选择为使该值最小化时的总配送天数。

【输入】

\(N\) \(K\) \(M\)
\(A_1\) \(A_2\) \(\ldots\) \(A_N\)

  • The first line contains three space-separated integers: \(N\) representing the number of destinations, \(K\) representing the number of packages that can be delivered per day, and \(M\) representing the upper limit of the capacity increase.
  • The second line contains \(N\) space-separated integers \(A_1, A_2, \ldots, A_N\) representing the number of packages for each destination.

【输出】

Output in a single line the minimum number of days required for Takahashi to complete all deliveries.

【输入样例】

3 3 2
7 3 5

【输出样例】

4

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int n, k, m, cnt;  // n: 怪物数量, k: 攻击力, m: 额外攻击力, cnt: 攻击次数

signed main()
{
    cin >> n >> k >> m;  // 输入怪物数, 基础攻击力, 额外攻击力
    k = k + m;  // 合并总攻击力
    for (int i = 1; i <= n; i++)  // 处理每个怪物
    {
        int x;
        cin >> x;  // 输入怪物血量
        cnt += (x + (k - 1)) / k;  // 向上取整除法
    }
    cout << cnt << endl;  // 输出总攻击次数
    return 0;
}

【运行结果】

3 3 2
7 3 5
4

C - Observatory with a Mountain View

【题目来源】

AtCoder:C - Observatory with a Mountain View

【题目描述】

Takahashi's hobby is mountain climbing, and he is compiling information about the mountains visible from observatories in various locations.
高桥的爱好是登山,他正在整理关于各个观测点所能看到的山峰信息。

In a certain mountainous region, there are \(N\) mountains. The \(i\)-th mountain has an elevation of \(Y_i\) meters and a beauty rating of \(P_i\).
在某个山区,有 \(N\) 座山峰。第 \(i\) 座山峰的海拔为 \(Y_i\) 米,美丽度为 \(P_i\)

Takahashi conducts \(Q\) surveys. In each survey, a reference elevation \(L_j\) is specified, and he wants to find the total beauty rating of all mountains whose elevation is at least \(L_j\).
高桥进行了 \(Q\) 次调查。每次调查中,会给定一个参考海拔 \(L_j\),他希望找出所有海拔不低于 \(L_j\) 的山峰的美丽度之和。

Find the answer for each survey.
求每次调查的答案。

【输入】

\(N\) \(Q\)
\(Y_1\) \(P_1\)
\(Y_2\) \(P_2\)
:
\(Y_N\) \(P_N\)
\(L_1\)
\(L_2\)
:
\(L_Q\)

  • The first line contains \(N\), the number of mountains, and \(Q\), the number of surveys, separated by a space.
  • From the 2nd line to the \((N + 1)\)-th line, information about each mountain is given.
  • The \((1 + i)\)-th line contains the elevation \(Y_i\) and the beauty rating \(P_i\) of the \(i\)-th mountain, separated by a space.
  • From the \((N + 2)\)-th line to the \((N + 1 + Q)\)-th line, the reference elevation for each survey is given.
  • The \((N + 1 + j)\)-th line contains the reference elevation \(L_j\) for the \(j\)-th survey.

【输出】

Output \(Q\) lines, each containing the answer to the corresponding survey. On the \(j\)-th line, output the total beauty rating of all mountains whose elevation is at least \(L_j\). If no such mountain exists, output \(0\).

【输入样例】

3 2
100 5
200 10
300 15
150
100

【输出样例】

25
30

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int n, q, sa[N];  // n: 物品数, q: 查询数, sa: 前缀和
struct Node
{
    int y, p;  // y: 高度限制, p: 价值
} a[N];

// 排序比较函数,按高度从大到小排序
bool cmp(Node x, Node y)
{
    return x.y > y.y;
}

// 二分查找第一个高度≥x的物品位置
int find(int x)
{
    int l = 0, r = n;  // 注意l从0开始
    while (l < r)
    {
        int mid = (l + r + 1) / 2;
        if (a[mid].y >= x)  // 如果中间高度≥x
        {
            l = mid;  // 向右搜索
        }
        else
        {
            r = mid - 1;  // 向左搜索
        }
    }
    return l;  // 返回位置
}

signed main()
{
    cin >> n >> q;  // 输入物品数和查询数
    for (int i = 1; i <= n; i++)  // 输入每个物品的高度和价值
    {
        cin >> a[i].y >> a[i].p;
    }
    sort(a + 1, a + n + 1, cmp);  // 按高度从大到小排序

    for (int i = 1; i <= n; i++)  // 计算前缀和
    {
        sa[i] = sa[i - 1] + a[i].p;
    }
    
    while (q--)  // 处理每个查询
    {
        int l;
        cin >> l;  // 输入限制高度
        int t = find(l);  // 二分查找位置
        cout << sa[t] << endl;  // 输出前缀和
    }
    return 0;
}

【运行结果】

3 2
100 5
200 10
300 15
150
25
100
30

D - Part-Time Job Shift Assignment

【题目来源】

AtCoder:D - Part-Time Job Shift Assignment

【题目描述】

Takahashi is the manager of a store with \(N\) part-time workers. He needs to complete \(M\) tasks on an upcoming holiday, and must assign exactly \(1\) part-time worker to each task.
高桥是一家拥有 \(N\) 名兼职员工的店长。他需要在即将到来的假日完成 \(M\) 项任务,并且必须为每项任务恰好分配 \(1\) 名兼职员工。

The part-time workers are numbered from \(1\) to \(N\), and the skill level of worker \(i\) is \(A_i\). The tasks are numbered from \(1\) to \(M\), and the required skill level of task \(j\) is \(D_j\).
兼职员工编号从 \(1\)\(N\),员工 \(i\) 的技能水平为 \(A_i\)。任务编号从 \(1\)\(M\),任务 \(j\) 所需的技能水平为 \(D_j\)

When worker \(i\) is assigned to task \(j\), their satisfaction is calculated as \(A_i - D_j\). Since a worker becomes dissatisfied if their satisfaction is negative, Takahashi wants to make an assignment such that every assigned worker's satisfaction is \(0\) or more (i.e., no one is dissatisfied).
当员工 \(i\) 被分配到任务 \(j\) 时,其满意度计算为 \(A_i - D_j\)。由于员工在满意度为负时会感到不满,高桥希望进行分配,使得每位被分配员工的满意度大于等于 \(0\)(即没有人感到不满)。

Specifically, he selects \(M\) workers out of the \(N\) part-time workers and assigns the selected \(M\) workers to the \(M\) tasks in a one-to-one correspondence. That is, letting \(f(j)\) denote the worker assigned to task \(j\), he considers an assignment \(f\) that satisfies all of the following conditions:
具体来说,他从 \(N\) 名兼职员工中选择 \(M\) 名员工,并将选出的 \(M\) 名员工一对一分配到 \(M\) 项任务。也就是说,设 \(f(j)\) 表示分配给任务 \(j\) 的员工,他考虑一个满足以下所有条件的分配 \(f\)

  • Exactly \(1\) part-time worker is assigned to each task \(j\) \((1 \leq j \leq M)\).
    每项任务 \(j\)\(1 \leq j \leq M\))恰好分配 \(1\) 名兼职员工。
  • Different tasks are assigned different workers. That is, if \(j \neq j'\), then \(f(j) \neq f(j')\). (Some workers may not be assigned to any task.)
    不同的任务分配给不同的员工。也就是说,如果 \(j \neq j'\),则 \(f(j) \neq f(j')\)。(有些员工可能没有被分配到任何任务。)
  • For every worker assigned to a task, their satisfaction is \(0\) or more. That is, for every task \(j\) \((1 \leq j \leq M)\), \(A_{f(j)} \geq D_j\) holds.
    对于每位被分配到任务的员工,其满意度大于等于 \(0\)。也就是说,对于每项任务 \(j\)\(1 \leq j \leq M\)),满足 \(A_{f(j)} \geq D_j\)

If an assignment satisfying these conditions exists, find the maximum value of the total satisfaction of the \(M\) assigned workers, \(\displaystyle\sum_{j=1}^{M}(A_{f(j)} - D_j)\). If no valid assignment exists, output \(-1\).
如果存在满足这些条件的分配,求 \(M\) 名被分配员工的总满意度 \(\displaystyle\sum_{j=1}^{M}(A_{f(j)} - D_j)\) 的最大值。如果不存在有效的分配,输出 \(-1\)

【输入】

\(N\) \(M\)
\(A_1\) \(A_2\) \(\ldots\) \(A_N\)
\(D_1\) \(D_2\) \(\ldots\) \(D_M\)

  • The first line contains an integer \(N\) representing the number of part-time workers and an integer \(M\) representing the number of tasks, separated by a space.
  • The second line contains integers \(A_1, A_2, \ldots, A_N\) representing the skill levels of each worker, separated by spaces.
  • The third line contains integers \(D_1, D_2, \ldots, D_M\) representing the required skill levels of each task, separated by spaces.

【输出】

If a valid assignment exists, output the maximum value of the total satisfaction as an integer on a single line. If no valid assignment exists, output \(-1\) on a single line.

【输入样例】

4 3
5 3 7 1
2 4 6

【输出样例】

3

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int n, m, sum;  // n: 商品数量, m: 优惠券数量, sum: 总支付金额
int a[N], d[N];  // a: 商品价格数组, d: 优惠券面值数组

signed main()
{
    cin >> n >> m;  // 输入商品数量和优惠券数量
    for (int i = 1; i <= n; i++)  // 读取商品价格
    {
        cin >> a[i];
    }
    for (int i = 1; i <= m; i++)  // 读取优惠券面值
    {
        cin >> d[i];
    }
    
    // 对商品价格和优惠券面值从大到小排序
    sort(a + 1, a + n + 1, greater<int>());
    sort(d + 1, d + m + 1, greater<int>());
    
    int i = 1, j = 1;  // i: 商品指针, j: 优惠券指针
    while (i <= n && j <= m)  // 贪心匹配
    {
        if (a[i] < d[j])  // 如果商品价格小于优惠券面值
        {
            i++;  // 跳过这个商品
        }
        else
        {
            sum += (a[i] - d[j]);  // 支付差价
            i++;  // 处理下一个商品
            j++;  // 使用下一张优惠券
        }
        // 调试输出
        // cout << "i j sum " << i << " " << j << " " << sum << endl;
    }
    if (j != m + 1)  // 如果还有优惠券未使用
    {
        cout << -1 << endl;  // 输出-1表示无法全部使用
    }
    else
    {
        cout << sum << endl;  // 输出总支付金额
    }
    return 0;
}

【运行结果】

4 3
5 3 7 1
2 4 6
3

E - Multiple Bonus

【题目来源】

AtCoder:E - Multiple Bonus

【题目描述】

Takahashi is a department manager who manages \(N\) employees. Each employee is assigned an employee number from \(1\) to \(N\), and the initial evaluation points of employee \(i\) are \(S_i\).
高桥是一位部门经理,管理着 \(N\) 名员工。每位员工被分配了一个从 \(1\)\(N\) 的员工编号,员工 \(i\) 的初始评分为 \(S_i\)

Let \(T_i\) denote the current evaluation points of employee \(i\). Initially, \(T_i = S_i\) (\(1 \leq i \leq N\)).
\(T_i\) 表示员工 \(i\) 当前的评分。初始时,\(T_i = S_i\)\(1 \leq i \leq N\))。

This company has a unique evaluation system. When a certain employee \(k\) (\(1 \leq k \leq N\)) achieves results as a team leader, bonus points corresponding to the achievement are added to the evaluation points of all employees whose employee numbers are multiples of \(k\) (\(k, 2k, 3k, \ldots\)) and are at most \(N\). Since \(k\) itself is a multiple of \(k\), it is included in the targets.
这家公司有一套独特的评分系统。当某位员工 \(k\)\(1 \leq k \leq N\))作为团队领导取得成果时,与成就对应的奖励分数会被加到所有员工编号是 \(k\) 的倍数(\(k, 2k, 3k, \ldots\))且不超过 \(N\) 的员工的评分上。由于 \(k\) 本身是 \(k\) 的倍数,因此也包含在目标中。

Takahashi performs \(Q\) operations on this evaluation system. Each operation is one of the following two types:
高桥对该评分系统执行 \(Q\) 次操作。每次操作是以下两种类型之一:

  • Operation \(1\): Given a positive integer \(k\) (\(1 \leq k \leq N\)) and a positive integer \(v\). Add \(v\) to the evaluation points \(T_j\) of all employees \(j\) whose employee numbers are multiples of \(k\) and are at most \(N\) (i.e., \(j = k, 2k, 3k, \ldots\) and \(j \leq N\)).
    操作 \(1\):给定一个正整数 \(k\)\(1 \leq k \leq N\))和一个正整数 \(v\)。将所有员工编号是 \(k\) 的倍数且不超过 \(N\) 的员工 \(j\)(即 \(j = k, 2k, 3k, \ldots\)\(j \leq N\))的评分 \(T_j\) 增加 \(v\)
  • Operation \(2\): Given a positive integer \(x\) (\(1 \leq x \leq N\)). Output the sum of the current evaluation points from employee \(1\) to employee \(x\): \(\displaystyle\sum_{i=1}^{x} T_i\).
    操作 \(2\):给定一个正整数 \(x\)\(1 \leq x \leq N\))。输出从员工 \(1\) 到员工 \(x\) 的当前评分之和:\(\displaystyle\sum_{i=1}^{x} T_i\)

For all operations of type \(2\), output the correct answer.
对于所有类型 \(2\) 的操作,输出正确答案。

【输入】

\(N\) \(Q\)
\(S_1\) \(S_2\) \(\ldots\) \(S_N\)
\(\mathrm{query}_1\)
\(\mathrm{query}_2\)
\(\vdots\)
\(\mathrm{query}_Q\)

  • The first line contains the number of employees \(N\) and the number of operations \(Q\), separated by a space.
  • The second line contains the initial evaluation points \(S_1, S_2, \ldots, S_N\) of each employee, separated by spaces.
  • The following \(Q\) lines each contain one operation.
  • For operation \(1\): given in the format 1 k v.
  • For operation \(2\): given in the format 2 x.

【输出】

Each time operation \(2\) is given, output the sum of evaluation points from employee \(1\) to employee \(x\) on one line.

【输入样例】

5 6
1 2 3 4 5
2 3
1 2 10
2 5
1 1 1
2 1
2 4

【输出样例】

6
35
2
34

【解题思路】

image

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int n, q, s[N], sa[N], tr[N], tag[N];  // s: 原始数组, sa: 前缀和, tr: 树状数组, tag: 分块标记

int lowbit(int x)  // 提出x的低位2次幂数
{
    return x & -x;
}
void add(int x, int c)  // 向后修:树状数组单点增加
{
    for (int i = x; i <= n; i += lowbit(i))
    {
        tr[i] += c;
    }
}
int query(int x)  // 向前查:树状数组前缀和查询
{
    int res = 0;
    for (int i = x; i; i -= lowbit(i))
    {
        res += tr[i];
    }
    return res;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> q;  // 输入数组长度和操作次数
    for (int i = 1; i <= n; i++)
    {
        cin >> s[i];  // 输入原始数组
        sa[i] = sa[i - 1] + s[i];  // 计算前缀和
    }
    int B = sqrt(n);  // 分块阈值
    while (q--)
    {
        int op;
        cin >> op;  // 操作类型
        if (op == 1)  // 修改操作
        {
            int k, v;
            cin >> k >> v;  // 对k的倍数位置增加v
            if (k <= B)  // 小k,使用分块标记
            {
                tag[k] += v;
            }
            else  // 大k,直接修改树状数组
            {
                for (int i = k; i <= n; i += k)
                {
                    add(i, v);
                }
            }
        }
        else  // 查询操作
        {
            int x;
            cin >> x;  // 查询前缀和
            int ans = sa[x] + query(x);  // 基础前缀和+树状数组修改
            for (int k = 1; k <= B; k++)  // 加上分块标记的贡献
            {
                ans += tag[k] * (x / k);
            }
            cout << ans << endl;
        }
    }
    return 0;
}

【运行结果】

5 6
1 2 3 4 5
2 3
6
1 2 10
2 5
35
1 1 1
2 1
2
2 4
34
posted @ 2026-03-30 09:00  团爸讲算法  阅读(1)  评论(0)    收藏  举报