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

A - Distribution of Sweets

【题目来源】

AtCoder:A - Distribution of Sweets

【题目描述】

Takahashi has been appointed as the organizer of a snack party.
高桥被任命为一次零食派对的组织者。

Takahashi has prepared \(N\) types of snacks, and there are \(A_i\) pieces of the \(i\)-th type of snack. He wants to distribute these snacks among the \(M\) friends attending the party.
高桥准备了 \(N\) 种零食,第 \(i\) 种零食有 \(A_i\) 块。他希望将这些零食分给参加派对的 \(M\) 位朋友。

For each type of snack, he will distribute the same number of pieces to all \(M\) people. For each type, find the number of pieces each person receives and the number of pieces that remain undistributed.
对于每种零食,他将分给所有 \(M\) 个人相同数量的块。对于每种零食,求每个人分得的块数以及剩余的未分发块数。

In other words, for each \(i = 1, 2, \ldots, N\), find the pair of non-negative integers \((Q_i, R_i)\) satisfying \(A_i = M \times Q_i + R_i\) and \(0 \le R_i < M\).
换句话说,对于每个 \(i = 1, 2, \ldots, N\),求满足 \(A_i = M \times Q_i + R_i\)\(0 \le R_i < M\) 的非负整数对 \((Q_i, R_i)\)

【输入】

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

  • The first line contains an integer \(N\) representing the number of types of snacks and an integer \(M\) representing the number of friends, separated by a space.
  • The second line contains integers \(A_1, A_2, \ldots, A_N\) representing the number of pieces of each type of snack, separated by spaces.

【输出】

Print \(N\) lines.

On the \(i\)-th line, print the quotient \(Q_i\) and the remainder \(R_i\) when \(A_i\) is divided by \(M\), separated by a space.

【输入样例】

3 4
10 7 3

【输出样例】

2 2
1 3
0 3

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int n, m;

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x;
        // 输出商和余数
        cout << x / m << " " << x % m << endl;
    }
    return 0;
}

【运行结果】

3 4
10 7 3
2 2
1 3
0 3

B - Shopping List

【题目来源】

AtCoder:B - Shopping List

【题目描述】

Takahashi is a university student who goes shopping for ingredients for his daily meals. A nearby supermarket sells \(N\) types of ingredients, each with a set price and classified as either a vegetable or meat.
高桥是一名大学生,每天都会去超市购买日常餐饮的食材。附近一家超市出售 \(N\) 种食材,每种都有固定价格,并被归类为蔬菜肉类

For health reasons, Takahashi has decided to purchase exactly \(1\) vegetable and exactly \(1\) meat item, for a total of \(2\) ingredients, on each shopping trip.
出于健康考虑,高桥决定每次购物时恰好购买 \(1\) 种蔬菜和 \(1\) 种肉类,总计 \(2\) 种食材。

Takahashi is planning his shopping over \(M\) days. However, the supermarket's stock varies by day, and not all ingredients are available for purchase every day.
高桥计划了 \(M\) 天的购物。然而,超市的库存每天变化,并非所有食材每天都可供购买。

For each ingredient \(i\) (\(1 \leq i \leq N\)), the price \(P_i\) and classification \(T_i\) are given. If \(T_i = 0\), ingredient \(i\) is a vegetable; if \(T_i = 1\), ingredient \(i\) is meat. Each ingredient belongs to exactly one of the two categories.
对于每种食材 \(i\)\(1 \leq i \leq N\)),给定价格 \(P_i\) 和分类 \(T_i\)。如果 \(T_i = 0\),食材 \(i\) 是蔬菜;如果 \(T_i = 1\),食材 \(i\) 是肉类。每种食材恰好属于这两个类别之一。

For each day \(j\) (\(1 \leq j \leq M\)), the number of available ingredients \(K_j\) and the list of available ingredient numbers \(S_{j,1}, S_{j,2}, \ldots, S_{j,K_j}\) are given. The same ingredient does not appear more than once in the available list for the same day.
对于每天 \(j\)\(1 \leq j \leq M\)),给定可购买的食材数量 \(K_j\) 以及可购买的食材编号列表 \(S_{j,1}, S_{j,2}, \ldots, S_{j,K_j}\)。同一种食材在同一天的可购列表中不会出现多次。

For each day, find the minimum total price when selecting \(1\) vegetable and \(1\) meat item from the ingredients available on that day. If the available ingredients do not include both a vegetable and a meat item, making it impossible to satisfy the condition, output \(-1\).
对于每一天,求从当天可购食材中选择 \(1\) 种蔬菜和 \(1\) 种肉类时的最低总价。如果可购食材中不包含蔬菜和肉类两者,无法满足条件,则输出 \(-1\)

【输入】

\(N\) \(M\)
\(P_1\) \(T_1\)
\(P_2\) \(T_2\)
\(\vdots\)
\(P_N\) \(T_N\)
\(K_1\) \(S_{1,1}\) \(S_{1,2}\) ... \(S_{1,K_1}\)
\(K_2\) \(S_{2,1}\) \(S_{2,2}\) ... \(S_{2,K_2}\)
\(\vdots\)
\(K_M\) \(S_{M,1}\) \(S_{M,2}\) ... \(S_{M,K_M}\)

  • The first line contains the integer \(N\) representing the number of ingredient types and the integer \(M\) representing the number of shopping days, separated by a space.
  • From the 2nd line to the \((N + 1)\)-th line, information about each ingredient is given.
  • The \((1 + i)\)-th line contains the price \(P_i\) of ingredient \(i\) and the classification value \(T_i\) (\(0\): vegetable, \(1\): meat), separated by a space.
  • From the \((N + 2)\)-th line to the \((N + M + 1)\)-th line, information about the ingredients available on each day is given.
  • The \((N + 1 + j)\)-th line contains the number of available ingredients \(K_j\) on day \(j\) and the available ingredient numbers \(S_{j,1}, S_{j,2}, \ldots, S_{j,K_j}\), separated by spaces.

【输出】

Output \(M\) lines. On the \(j\)-th line (\(1 \leq j \leq M\)), output the minimum total price when selecting \(1\) vegetable and \(1\) meat item from the ingredients available on day \(j\). If no valid selection exists, output \(-1\).

【输入样例】

5 3
100 0
200 1
150 0
300 1
250 0
3 1 2 3
2 1 5
4 1 3 4 5

【输出样例】

300
-1
400

【代码详解】

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

int n, m;
int p[N], t[N];  // p: 价格, t: 类型
int k, s[N];     // k: 查询数量, s: 用于存储查询结果

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> p[i] >> t[i];
    }

    while (m--)
    {
        cin >> k;
        int min0 = 1e9 + 5, min1 = 1e9 + 5;  // 分别存储类型0和类型1的最小价格
        for (int i = 1; i <= k; i++)
        {
            int x;
            cin >> x;
            // 更新对应类型的最小价格
            if (t[x] == 0 && p[x] < min0)
            {
                min0 = p[x];
            }
            if (t[x] == 1 && p[x] < min1)
            {
                min1 = p[x];
            }
        }
        // 如果某个类型没有找到最小值,输出-1
        if (min0 == 1e9 + 5 || min1 == 1e9 + 5)
        {
            cout << -1 << endl;
        }
        else
        {
            // 输出两种类型最小价格的和
            cout << min0 + min1 << endl;
        }
    }
    return 0;
}

【运行结果】

5 3
100 0
200 1
150 0
300 1
250 0
3 1 2 3
300
2 1 5
-1
4 1 3 4 5
400

C - Traffic Jam Report

【题目来源】

AtCoder:C - Traffic Jam Report

【题目描述】

Takahashi works at the traffic control center of a highway, monitoring traffic congestion.
高桥在高速公路的交通管制中心工作,监控交通拥堵情况。

The highway consists of \(N\) sections arranged in a line, numbered section \(1\), section \(2\), \(\ldots\), section \(N\) in order from the starting point. Each section has information about whether it is congested or not, and the state of section \(i\) is represented by \(S_i\) (\(S_i = 1\) means congested, \(S_i = 0\) means normal).
该高速公路由 \(N\) 个路段依次排列组成,从起点开始按顺序编号为路段 \(1\)、路段 \(2\)、……、路段 \(N\)。每个路段都有关于是否拥堵的信息,路段 \(i\) 的状态用 \(S_i\) 表示(\(S_i = 1\) 表示拥堵,\(S_i = 0\) 表示正常)。

Takahashi checks the congestion status of all sections on a monitor and makes reports focusing on places where congested sections are consecutive.
高桥在监控器上检查所有路段的拥堵状况,并重点报告拥堵路段连续出现的地方。

Here, we define a congestion block as follows:
此处,我们定义拥堵块如下:

A maximal contiguous subsequence of congested sections is called a congestion block. That is, when sections \(l, l+1, \ldots, r\) (\(1 \leq l \leq r \leq N\)) satisfy all of the following conditions, the group of sections from section \(l\) to section \(r\) is called a congestion block of length \(r - l + 1\):
一个最大的连续拥堵路段的子序列称为一个拥堵块。也就是说,当路段 \(l, l+1, \ldots, r\)\(1 \leq l \leq r \leq N\))满足以下所有条件时,从路段 \(l\) 到路段 \(r\) 的路段组称为一个长度为 \(r - l + 1\) 的拥堵块:

  • \(S_l = S_{l+1} = \cdots = S_r = 1\).
  • \(l = 1\) or \(S_{l-1} = 0\).
  • \(r = N\) or \(S_{r+1} = 0\).

For each congestion block, Takahashi makes the following judgment:
对于每个拥堵块,高桥做出以下判断:

  • If the length of the congestion block is \(K\) or more, it is judged as a large-scale congestion, and an emergency report is made once to his supervisor.
    如果拥堵块的长度大于等于 \(K\),则判定为大规模拥堵,并向其上级提交一次紧急报告
  • If the length of the congestion block is less than \(K\), it is handled with normal procedures (no emergency report is generated).
    如果拥堵块的长度小于 \(K\),则按正常流程处理(不生成紧急报告)。

After making this judgment for all congestion blocks, determine the total number of emergency reports generated.
对所有拥堵块做出此判断后,确定生成的紧急报告总数。

【输入】

\(N\) \(K\)
\(S_1\) \(S_2\) \(\ldots\) \(S_N\)

The first line contains the number of sections \(N\) and the threshold length \(K\) for congestion blocks that require an emergency report, separated by a space.

The second line contains the states of each section \(S_1, S_2, \ldots, S_N\), separated by spaces. \(S_i = 1\) means section \(i\) is congested, and \(S_i = 0\) means it is normal.

【输出】

Output the total number of emergency reports generated in a single line.

【输入样例】

10 3
0 1 1 1 0 1 1 0 1 1

【输出样例】

1

【代码详解】

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

int n, k, ans;
int s[N];  // 存储序列

int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
    {
        cin >> s[i];
    }
    int cnt = 0;      // 当前连续1的个数
    bool flag = 0;    // 标记当前连续段是否已计数
    for (int i = 1; i <= n; i++)
    {
        if (s[i] == 1)
        {
            cnt++;
            // 当连续1的个数达到k且未计数时
            if (cnt >= k && flag == 0)
            {
                ans++;
                flag = 1;  // 标记已计数
            }
        }
        else
        {
            cnt = 0;   // 重置连续1的计数
            flag = 0;  // 重置计数标记
        }
    }
    cout << ans << endl;
    return 0;
}

【运行结果】

10 3
0 1 1 1 0 1 1 0 1 1
1

D - Telephone Game of Messages

【题目来源】

AtCoder:D - Telephone Game of Messages

【题目描述】

There are \(N\) students in Takahashi's class, numbered from \(1\) to \(N\). The class plays a message-passing game (telephone game).
高桥的班上有 \(N\) 名学生,编号从 \(1\)\(N\)。这个班级在玩一个传话游戏(电话游戏)。

For each student \(i\) (\(1 \leq i \leq N\)), there is exactly one designated student \(T_i\) to whom they pass the message (\(T_i \neq i\)).
对于每名学生 \(i\)\(1 \leq i \leq N\)),恰好有一名指定的学生 \(T_i\) 作为其传话对象(\(T_i \neq i\))。

The game proceeds as follows. First, a starting student \(s\) is chosen. Let \(a_0 = s\), and for \(k \geq 0\), define the sequence \(a_0, a_1, a_2, \ldots\) by \(a_{k+1} = T_{a_k}\).
游戏进行如下:首先,选择一名起始学生 \(s\)。令 \(a_0 = s\),对于 \(k \geq 0\),通过 \(a_{k+1} = T_{a_k}\) 定义序列 \(a_0, a_1, a_2, \ldots\)

Initially, \(a_0\) is marked as "visited." Then, for \(k = 1, 2, \ldots\) in order, the following is repeated:
初始时,\(a_0\) 被标记为"已访问"。然后,依次对 \(k = 1, 2, \ldots\) 重复以下操作:

  • If \(a_k\) is already visited, the message stops there.
    如果 \(a_k\) 已被访问,则消息在此处停止。
  • Otherwise, mark \(a_k\) as visited and proceed to the next \(k\).
    否则,将 \(a_k\) 标记为已访问,并继续下一个 \(k\)

Since the number of students is finite, the message always stops after a finite number of steps.
由于学生人数有限,消息总是会在有限步后停止。

Let \(v\) denote the student reached when the process stops (i.e., \(a_k\) at the time of stopping). The student \(v\) was previously marked as visited, and repeatedly applying \(T\) starting from \(v\) will eventually return to \(v\). That is, following the path \(v, T_v, T_{T_v}, \ldots\) will eventually reach \(v\) again. The number of students on the path starting from \(v\) and returning to \(v\) (including \(v\) itself) is called the message loop length for starting student \(s\).
\(v\) 表示过程停止时到达的学生(即停止时的 \(a_k\))。学生 \(v\) 先前已被标记为已访问,从 \(v\) 开始重复应用 \(T\) 最终会回到 \(v\)。也就是说,沿着路径 \(v, T_v, T_{T_v}, \ldots\) 最终会再次到达 \(v\)。从 \(v\) 出发并回到 \(v\) 的路径上的学生人数(包括 \(v\) 自身)称为起始学生 \(s\)消息环长度

For each case where the message starts from student \(1\), student \(2\), ..., student \(N\), find the message loop length.
对于消息分别从学生 \(1\)、学生 \(2\)、……、学生 \(N\) 开始的情况,求消息环长度。

【输入】

\(N\)
\(T_1\) \(T_2\) \(\ldots\) \(T_N\)

  • The first line contains an integer \(N\), representing the number of students.
  • The second line contains \(N\) integers \(T_i\), separated by spaces, representing the recipient of each student \(i\)'s message.

【输出】

\(C_1\) \(C_2\) \(\ldots\) \(C_N\)

  • Let \(C_i\) be the message loop length when the message starts from student \(i\). Output \(C_i\) for \(i = 1, 2, \ldots, N\) in order, separated by spaces, on a single line.

【输入样例】

4
2 3 4 2

【输出样例】

3 3 3 3

【代码详解】

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

int n, t[N], ans[N];  // t: 指向的下一个位置, ans: 存储结果(环的长度)
bool vis[N];  // 访问标记

// 深度优先搜索,计算从节点u开始的环长度
void dfs(int u)
{
    // 如果已经计算过,直接返回
    if (ans[u])
    {
        return;
    }

    // 如果访问到已标记的节点,说明找到了环
    if (vis[u])
    {
        int len = 1;
        int v = t[u];
        // 计算环的长度
        while (v != u)
        {
            len++;
            v = t[v];
        }
        // 为环上所有节点设置结果
        ans[u] = len;
        v = t[u];
        while (v != u)
        {
            ans[v] = len;
            v = t[v];
        }
        return;
    }

    // 标记当前节点已访问
    vis[u] = true;
    dfs(t[u]);  // 递归探索下一个节点
    vis[u] = false;  // 回溯,取消标记
    
    // 如果当前节点的结果还未计算,则继承下一个节点的结果
    if (!ans[u])
    {
        ans[u] = ans[t[u]];
    }
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> t[i];
    }

    // 对每个未计算的节点进行DFS
    for (int i = 1; i <= n; i++)
    {
        if (!ans[i])
        {
            // 注释掉的调试代码
            // cout << "i " << i << endl;
            // for (int i=1; i<=n; i++)
            //     cout << vis[i] << " ";
            // cout << endl;
            dfs(i);
        }
    }

    // 输出结果
    for (int i = 1; i <= n; i++)
    {
        cout << ans[i] << " ";
    }
    cout << endl;
    return 0;
}

【运行结果】

4
2 3 4 2
3 3 3 3

E - Optimizing Team Division

【题目来源】

AtCoder:E - Optimizing Team Division

【题目描述】

Takahashi has been assigned the task of dividing participants of a programming camp into teams.
高桥被分配了一项任务,需要将一个编程训练营的参与者分成不同小组。

There are \(N\) participants in the camp, and the skill level of the \(i\)-th participant \((1 \leq i \leq N)\) is \(A_i\). Takahashi will select \(1\) or more participants from these \(N\) people to form exactly \(1\) team. Each participant is either selected or not selected, and the same participant cannot be selected more than once. Participants who are not selected will not participate in this team activity.
训练营有 \(N\) 名参与者,第 \(i\) 名参与者(\(1 \leq i \leq N\))的技能水平为 \(A_i\)。高桥将从这 \(N\) 人中选出 \(1\) 名或更多参与者,组成恰好 \(1\) 个小组。每名参与者要么被选中,要么不被选中,同一名参与者不能被多次选择。未被选中的参与者将不参加这个小组活动。

The "cohesion" of a team is defined as follows:
小组的"凝聚力"定义如下:

  • The greatest common divisor (GCD) of the skill levels of all selected team members, multiplied by the number of team members.
    所有被选中的小组成员技能水平的最大公约数(GCD) 乘以小组成员人数。

That is, if \(k\) people \((k \geq 1)\) are selected from the \(N\) participants, and the skill levels of the selected members are \(B_1, B_2, \ldots, B_k\), then the cohesion is
也就是说,如果从 \(N\) 名参与者中选出 \(k\) 人(\(k \geq 1\)),且被选成员的技能水平为 \(B_1, B_2, \ldots, B_k\),则凝聚力为

\(\gcd(B_1, B_2, \ldots, B_k) \times k\)

Here, when \(k = 1\), we define \(\gcd(B_1) = B_1\).
这里,当 \(k = 1\) 时,我们定义 \(\gcd(B_1) = B_1\)

Find the maximum value of cohesion when Takahashi chooses the selection optimally.
求高桥在最优选择时,所能获得的最大凝聚力值。

【输入】

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

  • The first line contains a positive integer \(N\), representing the number of participants.
  • The second line contains \(N\) positive integers \(A_1, A_2, \ldots, A_N\) separated by spaces, representing the skill levels of each participant.

【输出】

Print the maximum value of cohesion in a single line.

【输入样例】

5
2 3 4 6 9

【输出样例】

9

【解题思路】

image

【代码详解】

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

int n;
int a[N];
int cnt[N], ans;  // cnt数组用于统计每个数字出现的次数

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x;
        cnt[x]++;  // 记录数字x出现的次数
    }
    // 遍历所有可能的公约数i
    for (int i = 1; i <= 1000000; i++)
    {
        int sum = 0;
        // 统计所有是i的倍数的数字的总出现次数
        for (int j = 1; i * j <= 1000000; j++)
        {
            sum += cnt[i * j];
        }
        // 更新答案:最大公约数i * 能被i整除的数字个数
        ans = max(ans, i * sum);
    }

    cout << ans << endl;
    return 0;
}

【运行结果】

5
2 3 4 6 9
posted @ 2026-03-21 19:31  团爸讲算法  阅读(3)  评论(0)    收藏  举报