AtCoder Weekday Contest 0017 Beta题解(AWC 0017 Beta A-E)
A - Organizing the Bookshelf
【题目来源】
AtCoder:A - Organizing the Bookshelf
【题目描述】
Takahashi is trying to choose books to reread while organizing his bookshelf.
高桥在整理书架时,正试图选择要重读的书籍。
There are \(N\) books on the bookshelf, and for the \(i\)-th book (\(1 \leq i \leq N\)), a value \(C_i\) representing "the number of times it has been read so far" and a value \(D_i\) representing "satisfaction" are recorded.
书架上有 \(N\) 本书,对于第 \(i\) 本书(\(1 ≤ i ≤ N\)),记录有表示"截至目前已被阅读的次数"的值 \(C_i\) 和表示"满意度"的值 \(D_i\)。
Takahashi decided to prioritize rereading books that he has read fewer times. Specifically, he wants to select all books that have been read \(K\) times or fewer as candidates for rereading, and he wants to know the total satisfaction of those books.
高桥决定优先重读阅读次数较少的书籍。具体来说,他想选择所有已被阅读 \(K\) 次或更少的书籍作为重读的候选,并且他想知道这些书籍的总满意度。
From the \(N\) books, find the total satisfaction of all books that have been read \(K\) times or fewer. If there are no such books, the total is \(0\).
从这 \(N\) 本书中,找出所有已被阅读 \(K\) 次或更少的书籍的总满意度。如果没有这样的书籍,则总和为 \(0\)。
【输入】
\(N\) \(K\)
\(C_1\) \(D_1\)
\(C_2\) \(D_2\)
\(\vdots\)
\(C_N\) \(D_N\)
- The first line contains an integer \(N\) representing the number of books and an integer \(K\) representing the upper limit on the number of times read, separated by a space.
- In the following \(N\) lines, the \(i\)-th line (\(1 \leq i \leq N\)) contains the number of times the \(i\)-th book has been read \(C_i\) and its satisfaction \(D_i\), separated by a space.
【输出】
Output in one line the total satisfaction of books that have been read \(K\) times or fewer. If there are no such books, output \(0\).
【输入样例】
5 2
1 10
3 20
0 15
2 30
5 25
【输出样例】
55
【解题思路】

【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, k, ans; // n: 数据对数量,k: 阈值,ans: 结果
signed main()
{
cin >> n >> k; // 读入数据对数量和阈值
for (int i = 1; i <= n; i++) // 遍历每个数据对
{
int c, d;
cin >> c >> d; // 读入c和d
if (c <= k) // 如果c小于等于阈值k
{
ans += d; // 将d累加到结果中
}
}
cout << ans << endl; // 输出结果
return 0;
}
【运行结果】
5 2
1 10
3 20
0 15
2 30
5 25
55
B - Brightness of Street Lights
【题目来源】
AtCoder:B - Brightness of Street Lights
【题目描述】
Takahashi works as a street light manager at the city hall. The street he is responsible for has \(N\) street lights arranged in a row, numbered \(1, 2, \ldots, N\) from left to right.
高桥在市政府担任路灯管理员。他负责的街道上有 \(N\) 盏路灯排成一行,从左到右编号为 \(1, 2, …, N\)。
Each street light \(i\) is given an integer value \(A_i\) representing its initial brightness. When Takahashi performs maintenance on street light \(i\), the effect extends not only to that street light but also to its adjacent street lights. Specifically, the brightness of all street lights among \(i-1\), \(i\), \(i+1\) whose numbers are between \(1\) and \(N\) (inclusive) increases by \(1\).
每盏路灯 \(i\) 被赋予一个表示其初始亮度的整数值 \(A_i\)。当高桥对路灯 \(i\) 进行维护时,效果不仅作用于该路灯,还会影响其相邻的路灯。具体来说,所有编号在 \(i-1\)、\(i\)、\(i+1\) 之间且介于 \(1\) 到 \(N\)(包含)的路灯的亮度增加 \(1\)。
Takahashi performs a total of \(M\) maintenance operations. In the \(j\)-th operation \((1 \leq j \leq M)\), he performs maintenance on street light \(B_j\). Note that the same street light may be maintained multiple times.
高桥总共执行 \(M\) 次维护操作。在第 \(j\) 次操作(\(1 ≤ j ≤ M\))中,他对路灯 \(B_j\) 进行维护。注意,同一盏路灯可能被维护多次。
Determine the brightness of each street light after all operations are completed.
确定所有操作完成后每盏路灯的亮度。
【输入】
\(N\) \(M\)
\(A_1\) \(A_2\) \(\ldots\) \(A_N\)
\(B_1\) \(B_2\) \(\ldots\) \(B_M\)
- The first line contains an integer \(N\) representing the number of street lights and an integer \(M\) representing the number of maintenance operations, separated by a space.
- The second line contains integers \(A_1, A_2, \ldots, A_N\) representing the initial brightness of each street light, separated by spaces.
- The third line contains integers \(B_1, B_2, \ldots, B_M\) representing the street light numbers to be maintained in each operation, separated by spaces.
【输出】
Print the brightness of each street light after all operations are completed, in order from street light \(1\) to street light \(N\), separated by spaces, on a single line.
【输入样例】
5 3
1 2 3 4 5
2 4 4
【输出样例】
2 3 6 6 7
【解题思路】

【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int n, m; // n: 数组长度,m: 操作次数
int a[N]; // 数组
signed main()
{
cin >> n >> m; // 读入数组长度和操作次数
for (int i = 1; i <= n; i++)
{
cin >> a[i]; // 读入数组元素
}
for (int i = 1; i <= m; i++) // 执行m次操作
{
int b;
cin >> b; // 读入操作位置
a[b]++; // 当前位置加1
a[b + 1]++; // 后一个位置加1
a[b - 1]++; // 前一个位置加1
}
for (int i = 1; i <= n; i++) // 输出最终数组
{
cout << a[i] << " ";
}
cout << endl;
return 0;
}
【运行结果】
5 3
1 2 3 4 5
2 4 4
2 3 6 6 7
C - Same Color Check in the Flower Bed
【题目来源】
AtCoder:C - Same Color Check in the Flower Bed
【题目描述】
Takahashi is in charge of managing the school's flower bed. The flower bed has \(N\) plots arranged in a row, and the \(i\)-th plot from the left (\(1 \leq i \leq N\)) has a flower of color \(C_i\) planted in it. Here, flower colors are represented by positive integers.
高桥负责管理学校的花坛。花坛有 \(N\) 个地块排成一行,从左数第 \(i\) 个地块(\(1 ≤ i ≤ N\))种有颜色为 \(C_i\) 的花。此处,花的颜色用正整数表示。
Aoki asked Takahashi \(Q\) questions to investigate the appearance of the flower bed. In the flower bed, if two adjacent plots have flowers of the same color, there is little visual variation and it looks monotonous. Therefore, Aoki wants to know how many places within a specified range have adjacent plots with the same flower color.
青木问了高桥 \(Q\) 个问题来调查花坛的外观。在花坛中,如果两个相邻地块的花颜色相同,视觉变化就很小,看起来单调。因此,青木想知道指定范围内有多少个位置存在相邻地块花颜色相同的情况。
In the \(j\)-th question (\(1 \leq j \leq Q\)), a range from plot \(L_j\) to plot \(R_j\) is specified. Find the number of integers \(i\) satisfying \(L_j \leq i \leq R_j - 1\) and \(C_i = C_{i+1}\). In other words, among the pairs of adjacent plots within the contiguous interval from plot \(L_j\) to plot \(R_j\), count the number of pairs where the flower colors match.
在第 \(j\) 个问题(\(1 ≤ j ≤ Q\))中,指定了从地块 \(L_j\) 到地块 \(R_j\) 的范围。求满足 \(L_j ≤ i ≤ R_j - 1\) 且 \(C_i = C_{i+1}\) 的整数 \(i\) 的数量。换句话说,在地块 \(L_j\) 到地块 \(R_j\) 的连续区间内相邻的地块对中,统计花朵颜色匹配的对数。
Find the answer for each of the \(Q\) questions.
求这 \(Q\) 个问题中每个问题的答案。
【输入】
\(N\) \(Q\)
\(C_1\) \(C_2\) \(\ldots\) \(C_N\)
\(L_1\) \(R_1\)
\(L_2\) \(R_2\)
\(\vdots\)
\(L_Q\) \(R_Q\)
- The first line contains the integer \(N\) representing the number of plots and the integer \(Q\) representing the number of questions, separated by a space.
- The second line contains the integers \(C_1, C_2, \ldots, C_N\) representing the flower color of each plot, separated by spaces.
- In the following \(Q\) lines, the \(j\)-th line contains the left endpoint \(L_j\) and the right endpoint \(R_j\) of the range specified in the \(j\)-th question, separated by a space.
【输出】
Output \(Q\) lines. On the \(j\)-th line (\(1 \leq j \leq Q\)), output the answer to the \(j\)-th question, that is, the number of integers \(i\) satisfying \(L_j \leq i \leq R_j - 1\) and \(C_i = C_{i+1}\).
【输入样例】
5 3
1 1 2 2 2
1 5
1 3
3 5
【输出样例】
3
1
2
【解题思路】

【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int n, q; // n: 数组长度,q: 查询次数
int c[N], a[N], sa[N]; // c: 原数组,a: 标记数组,sa: 前缀和数组
signed main()
{
cin >> n >> q; // 读入数组长度和查询次数
for (int i = 1; i <= n; i++)
{
cin >> c[i]; // 读入原数组
}
// 构建标记数组a
for (int i = 2; i <= n; i++)
{
if (c[i] == c[i - 1]) // 如果当前元素等于前一个元素
{
a[i] = 1; // 标记为1
}
}
// 构建前缀和数组
for (int i = 1; i <= n; i++)
{
sa[i] = sa[i - 1] + a[i]; // 计算前缀和
}
// 调试输出
// for (int i=1; i<=n; i++)
// cout << sa[i] << " ";
// cout << endl;
while (q--) // 处理每个查询
{
int l, r;
cin >> l >> r; // 读入查询区间
cout << sa[r] - sa[l] << endl; // 输出区间和
}
return 0;
}
【运行结果】
5 3
1 1 2 2 2
1 5
3
1 3
1
3 5
2
D - Team Building
【题目来源】
AtCoder:D - Team Building
【题目描述】
Takahashi is in charge of forming a project team at his company.
高桥负责在他的公司组建一个项目团队。
There are \(N\) employees in the company, each assigned an employee number from \(1\) to \(N\). The ability value of employee \(i\) is \(A_i\).
公司有 \(N\) 名员工,每名员工被分配了从 \(1\) 到 \(N\) 的员工编号。员工 \(i\) 的能力值为 \(A_i\)。
Takahashi has decided to select exactly \(K\) employees from the \(N\) employees to form a team. The same employee cannot be selected more than once, and each employee is either selected for the team or not.
高桥决定从这 \(N\) 名员工中恰好选择 \(K\) 名员工组成一个团队。同一名员工不能被选择超过一次,每名员工要么被选入团队,要么不被选入。
However, there may be compatibility issues between some employees. \(M\) "incompatible pairs" are given, where the \(j\)-th pair consists of employee \(U_j\) and employee \(V_j\). If both of these employees are selected for the team, their coordination suffers and the team's overall strength decreases by \(B_j\). If only one of the pair is selected, or neither is selected, no decrease occurs.
然而,某些员工之间可能存在兼容性问题。给出了 \(M\) 个"不兼容对",其中第 \(j\) 对包含员工 \(U_j\) 和员工 \(V_j\)。如果这两名员工都被选入团队,他们的协作会受到影响,团队的整体实力会下降 \(B_j\)。如果只选择了其中一名,或者都未选择,则不会发生下降。
Specifically, let \(S\) (\(S \subseteq \{1, 2, \ldots, N\}\), \(|S| = K\)) be the set of employee numbers of the \(K\) selected employees. The team's overall strength is defined as follows:
具体来说,设 \(S\) (\(S \subseteq \{1, 2, \ldots, N\}\), \(|S| = K\)) 为所选 \(K\) 名员工的员工编号集合。团队的整体实力定义如下:
\(\sum_{i \in S} A_i \ - \sum_{\substack{1 \leq j \leq M \\ U_j \in S \text{ and } V_j \in S}} B_j\)
That is, it is the total ability values of the \(K\) selected employees minus the total decrease from all incompatible pairs where both members are included in \(S\).
也就是说,它是所选 \(K\) 名员工的总能力值减去所有不兼容对(其两名成员都包含在 \(S\) 中)的总下降值。
When Takahashi selects \(K\) employees to maximize the team's overall strength, find the maximum value of the team's overall strength. Note that the overall strength may be negative, but even in that case, output the maximum value as is.
当高桥选择 \(K\) 名员工以最大化团队的整体实力时,求团队整体实力的最大值。注意,整体实力可能为负数,但即使在这种情况下,也请原样输出最大值。
【输入】
\(N\) \(M\) \(K\)
\(A_1\) \(A_2\) \(\ldots\) \(A_N\)
\(U_1\) \(V_1\) \(B_1\)
\(U_2\) \(V_2\) \(B_2\)
\(\vdots\)
\(U_M\) \(V_M\) \(B_M\)
- The first line contains the number of employees \(N\), the number of incompatible pairs \(M\), and the number of employees to select for the team \(K\), separated by spaces.
- The second line contains the ability values of each employee \(A_1, A_2, \ldots, A_N\), separated by spaces.
- The following \(M\) lines (from the 3rd line to the \((M + 2)\)-th line) contain the information about the incompatible pairs. If \(M = 0\), this part does not exist.
- The \((2 + j)\)-th line contains the employee numbers \(U_j\) and \(V_j\) forming the \(j\)-th incompatible pair, and the decrease in overall strength \(B_j\), separated by spaces.
【输出】
Output the maximum value of the team's overall strength in a single line.
【输入样例】
4 2 2
10 8 6 5
1 2 3
3 4 2
【输出样例】
16
【解题思路】

【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 20, M = N * N, INF = -1e18;
int n, m, k; // n: 节点数,m: 边数,k: 需要选择的节点数
int a[N]; // 每个节点的权值
int dp[1 << N][N + 5]; // dp[mask][cnt]: 状态为mask,已选cnt个节点时的最大价值
int h[N], e[M], w[M], ne[M], idx; // 邻接表
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
signed main()
{
cin >> n >> m >> k; // 读入节点数、边数、需要选择的节点数
for (int i = 1; i <= n; i++)
{
cin >> a[i]; // 读入每个节点的权值
}
memset(h, -1, sizeof(h)); // 初始化邻接表
for (int i = 1; i <= m; i++)
{
int u, v, b;
cin >> u >> v >> b;
add(u, v, b), add(v, u, b); // 添加无向边
}
memset(dp, -0x3f3f3f3f, sizeof(dp)); // 初始化DP数组为极小值
// 另一种初始化方式(被注释掉)
// for (int mask = 0; mask<(1<<n); mask++)
// for (int cnt=0; cnt<=k; cnt++)
// dp[mask][cnt] = INF;
dp[0][0] = 0; // 初始状态:没有选择任何节点,价值为0
// 状态压缩DP
for (int mask = 0; mask < (1 << n); mask++)
{
int cnt = __builtin_popcount(mask); // 当前已选节点数
if (cnt > k) // 如果已选节点超过k,跳过
{
continue;
}
for (int u = 1; u <= n; u++) // 尝试添加新节点u
{
if (mask & (1 << (u - 1))) // 如果u已经被选择,跳过
{
continue;
}
int new_mask = mask | (1 << (u - 1)); // 新状态掩码
int new_cnt = cnt + 1; // 新已选节点数
if (new_cnt > k) // 如果超过k,跳过
{
continue;
}
int penalty = 0; // 惩罚值
for (int i = h[u]; i != -1; i = ne[i]) // 遍历u的所有邻接点
{
int v = e[i];
if (mask & (1 << (v - 1))) // 如果v已经被选择
{
penalty += w[i]; // 添加边权作为惩罚
}
}
int new_value = dp[mask][cnt] + a[u] - penalty; // 新价值
if (new_value > dp[new_mask][new_cnt]) // 如果更好,更新
{
dp[new_mask][new_cnt] = new_value;
}
}
}
int ans = INF;
for (int mask = 0; mask < (1 << n); mask++) // 遍历所有状态
{
if (__builtin_popcount(mask) == k) // 如果恰好选择了k个节点
{
ans = max(ans, dp[mask][k]); // 更新答案
}
}
cout << ans << endl;
return 0;
}
【运行结果】
4 2 2
10 8 6 5
1 2 3
3 4 2
16
E - Optimization of Delivery Routes
【题目来源】
AtCoder:E - Optimization of Delivery Routes
【题目描述】
Takahashi works as a delivery driver. There are a total of \(N\) locations relevant to today's deliveries, each numbered from \(1\) to \(N\). Location \(1\) is the distribution center (serving as both the starting point and the return point), and locations \(2\) through \(N\) are the destinations where packages must be delivered.
高桥是一名送货司机。今天配送总共涉及 \(N\) 个地点,每个地点编号从 \(1\) 到 \(N\)。地点 \(1\) 是配送中心(既作为起点也作为返回点),地点 \(2\) 到 \(N\) 是需要送达包裹的目的地。
Each location \(i\) is positioned at coordinates \((X_i, Y_i)\) on a two-dimensional plane. Note that different locations may share the same coordinates.
每个地点 \(i\) 位于二维平面上的坐标 \((X_i, Y_i)\)。注意,不同的地点可能共享相同的坐标。
Takahashi plans a tour route starting from the distribution center (location \(1\)), visiting all destinations (locations \(2\) through \(N\)) exactly once each, and then returning to the distribution center (location \(1\)). Specifically, he chooses a permutation \((p_1, p_2, \ldots, p_{N-1})\) of \((2, 3, \ldots, N)\) and travels in the order:
高桥计划一条从配送中心(地点 \(1\))出发的巡回路线,访问所有目的地(地点 \(2\) 到 \(N\))各恰好一次,然后返回配送中心(地点 \(1\))。具体来说,他选择一个 \((2, 3, …, N)\) 的排列 \((p_1, p_2, …, p_{N-1})\),并按以下顺序行进:
\(1 \to p_1 \to p_2 \to \cdots \to p_{N-1} \to 1\)
The fuel cost for Takahashi's delivery truck to travel directly from coordinates \((a, b)\) to coordinates \((c, d)\) is calculated as \((a - c)^2 + (b - d)^2\).
高桥的送货卡车直接从坐标 \((a, b)\) 行驶到坐标 \((c, d)\) 的燃料成本计算公式为 \((a - c)² + (b - d)²\)。
The total fuel cost of the tour route is the sum of the travel costs between each pair of consecutive locations along the route. Specifically, the fuel cost of the above tour route is:
巡回路线的总燃料成本是路线上每一对连续地点之间的行驶成本之和。具体来说,上述巡回路线的燃料成本为:
\(\mathrm{dist}(1, p_1) + \sum_{k=1}^{N-2} \mathrm{dist}(p_k, p_{k+1}) + \mathrm{dist}(p_{N-1}, 1)\)
where \(\mathrm{dist}(i, j) = (X_i - X_j)^2 + (Y_i - Y_j)^2\) represents the travel cost from location \(i\) to location \(j\).
其中 \(\mathrm{dist}(i, j) = (X_i - X_j)^2 + (Y_i - Y_j)^2\) 表示从地点 \(i\) 到地点 \(j\) 的行驶成本。
Takahashi wants to minimize the total fuel cost of the tour route by freely choosing the order in which he visits the destinations. Travel is done directly along the tour route; he cannot pass through other locations or arbitrary coordinates along the way.
高桥希望通过自由选择访问目的地的顺序,来最小化巡回路线的总燃料成本。旅行是沿着巡回路线上直接进行的;他不能途中经过其他地点或任意坐标。
Find the minimum fuel cost.
求最小燃料成本。
【输入】
\(N\)
\(X_1\) \(Y_1\)
\(X_2\) \(Y_2\)
\(\vdots\)
\(X_N\) \(Y_N\)
- The first line contains an integer \(N\) representing the number of locations.
- Lines \(2\) through \(N + 1\) give the coordinates of each location.
- Line \(1 + i\) contains the \(x\)-coordinate \(X_i\) and the \(y\)-coordinate \(Y_i\) of location \(i\), separated by a space.
【输出】
Output the minimum total fuel cost of the tour route as an integer on a single line.
【输入样例】
2
0 0
1 1
【输出样例】
4
【解题思路】

【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 20, INF = 1e9;
int n, x[N], y[N]; // n: 点数,x[], y[]: 点的坐标
int dp[1 << N][N]; // dp[mask][u]: 访问过mask中的点,当前在点u的最小花费
int dist[N][N]; // dist[i][j]: 点i到点j的距离平方
int main()
{
cin >> n; // 读入点数
for (int i = 1; i <= n; i++)
{
cin >> x[i] >> y[i]; // 读入每个点的坐标
}
// 计算所有点对之间的距离平方
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
dist[i][j] = (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
}
}
memset(dp, 0x3f, sizeof(dp)); // 初始化DP数组为极大值
dp[1][1] = 0; // 初始状态:从点1开始,只访问了点1,花费为0
// 状态压缩DP
for (int mask = 1; mask < (1 << n); mask++) // 遍历所有状态掩码
{
for (int u = 1; u <= n; u++) // 遍历当前所在点
{
if (dp[mask][u] == INF) // 当前状态不可达
{
continue;
}
for (int v = 1; v <= n; v++) // 尝试前往下一个点v
{
if (mask & (1 << (v - 1))) // 如果点v已经被访问过
{
continue;
}
int new_mask = mask | (1 << (v - 1)); // 新状态掩码
int new_cost = dp[mask][u] + dist[u][v]; // 新花费
if (new_cost < dp[new_mask][v]) // 如果新花费更小
{
dp[new_mask][v] = new_cost; // 更新DP值
}
}
}
}
int ans = INF;
for (int i = 1; i <= n; i++) // 遍历所有点作为终点
{
if (dp[(1 << n) - 1][i] != INF) // 如果所有点都被访问过
{
int tot = dp[(1 << n) - 1][i] + dist[i][1]; // 回到起点1的花费
ans = min(ans, tot); // 更新最小花费
}
}
cout << ans << endl; // 输出结果
return 0;
}
【运行结果】
2
0 0
1 1
4
浙公网安备 33010602011771号