AtCoder Weekday Contest 0012 Beta题解(AWC 0012 Beta A-E)
A - Typhoon Damage Survey
【题目来源】
AtCoder:A - Typhoon Damage Survey
【题目描述】
Takahashi is the caretaker of an orchard. There are \(N\) fruit trees planted in this orchard, numbered \(1, 2, \ldots, N\). The height of fruit tree \(i\) is \(H_i\).
高桥是一个果园的看护人。这个果园中种有 \(N\) 棵果树,编号为 \(1, 2, …, N\)。果树 \(i\) 的高度为 \(H_i\)。
Last night, a large typhoon passed through this area. Due to the typhoon's strong winds, fruit trees with height \(T\) or less had not yet developed sufficient roots and all fell over. That is, fruit tree \(i\) has fallen if and only if \(H_i \leq T\).
昨晚,一场强台风经过了这个地区。由于台风的强风,高度不超过 \(T\) 的果树因根系尚未充分发育而全部倒伏。也就是说,果树 \(i\) 倒伏当且仅当 \(H_i ≤ T\)。
To restore the orchard, Takahashi decided to replant all the fallen fruit trees. The cost to replant fruit tree \(i\) and restore it to its original state is \(C_i\).
为了恢复果园,高桥决定重新种植所有倒伏的果树。重新种植果树 \(i\) 并将其恢复到原始状态的成本是 \(C_i\)。
Find the total cost required to restore all fallen fruit trees to their original state.
求将所有倒伏的果树恢复到原始状态所需的总成本。
【输入】
Input is given from standard input in the following format.
\(N\) \(T\)
\(H_1\) \(H_2\) \(\ldots\) \(H_N\)
\(C_1\) \(C_2\) \(\ldots\) \(C_N\)
- The first line contains an integer \(N\) representing the number of fruit trees and an integer \(T\) representing the height threshold for trees falling, separated by a space.
- The second line contains integers \(H_1, H_2, \ldots, H_N\) representing the height of each fruit tree, separated by spaces.
- The third line contains integers \(C_1, C_2, \ldots, C_N\) representing the restoration cost for replanting each fruit tree, separated by spaces.
【输出】
Output in a single line the total cost required to restore all fallen fruit trees (fruit trees \(i\) satisfying \(H_i \leq T\)). If no fruit trees have fallen, output \(0\). Include a newline at the end.
【输入样例】
5 3
1 5 3 4 2
10 20 30 40 50
【输出样例】
90
【解题思路】

【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int n, t, h[N], c[N], ans; // n: 物品数量,t: 阈值
// h: 高度数组,c: 价值数组,ans: 总价值
signed main()
{
cin >> n >> t; // 读入物品数量和阈值
for (int i = 1; i <= n; i++)
{
cin >> h[i]; // 读入每个物品的高度
}
for (int i = 1; i <= n; i++)
{
cin >> c[i]; // 读入每个物品的价值
}
// 统计高度不超过阈值的物品的总价值
for (int i = 1; i <= n; i++)
{
if (h[i] <= t) // 如果高度不超过阈值
{
ans += c[i]; // 累加价值
}
}
cout << ans << endl; // 输出总价值
return 0;
}
【运行结果】
5 3
1 5 3 4 2
10 20 30 40 50
90
B - Factory Quality Inspection
【题目来源】
AtCoder:B - Factory Quality Inspection
【题目描述】
Takahashi is in charge of quality control at a factory. Today, \(N\) products are coming along a conveyor belt.
高桥负责一家工厂的质量控制。今天,有 \(N\) 件产品沿传送带而来。
Each product has a measured "internal temperature", and the internal temperature of the \(i\)-th product is \(W_i\). A product whose internal temperature is at least the threshold \(T\) is a defective product. If a defective product is shipped as-is, a loss of \(D\) is incurred per product. Products with internal temperature less than \(T\) are not defective, so no loss is incurred when they are shipped.
每件产品都有一个测量到的"内部温度",第 \(i\) 件产品的内部温度为 \(W_i\)。内部温度至少为阈值 \(T\) 的产品是有缺陷的产品。如果有缺陷的产品被原样发货,每件产品会产生 \(D\) 的损失。内部温度小于 \(T\) 的产品没有缺陷,因此它们发货时不会产生损失。
Takahashi can select any number of products on the conveyor belt and apply "additional cooling treatment" to them. Each product can receive additional cooling treatment at most once, at a cost of \(C\) per product. If a defective product receives additional cooling treatment, it is no longer defective and can be shipped without incurring any loss. Additional cooling treatment can also be applied to non-defective products, but since those products would not have incurred any loss anyway, only the cost \(C\) is wasted.
高桥可以选择传送带上任意数量的产品,对它们进行"额外冷却处理"。每件产品最多可以接受一次额外冷却处理,每件产品的成本为 \(C\)。如果有缺陷的产品接受了额外冷却处理,它将不再有缺陷,可以无损失发货。额外冷却处理也可以应用于无缺陷的产品,但由于这些产品本来就不会产生任何损失,只会浪费成本 \(C\)。
All products will ultimately be shipped. Takahashi wants to minimize the sum of the total cost of additional cooling treatments and the total loss from shipping defective products that did not receive additional cooling treatment. Given that he can freely choose which products to apply additional cooling treatment to, find the minimum value of this sum.
所有产品最终都将被发货。高桥希望最小化额外冷却处理的总成本与未接受额外冷却处理的有缺陷产品发货造成的总损失之和。假设他可以自由选择对哪些产品应用额外冷却处理,求这个总和的最小值。
【输入】
\(N\) \(T\) \(C\) \(D\)
\(W_1\) \(W_2\) \(\ldots\) \(W_N\)
- The first line contains \(N\) representing the number of products, \(T\) representing the threshold for defective products, \(C\) representing the cost per additional cooling treatment, and \(D\) representing the loss per defective product, separated by spaces.
- The second line contains \(W_1, W_2, \ldots, W_N\) representing the internal temperatures of the products, separated by spaces.
【输出】
Output the minimum value of the sum of total cost and total loss as an integer on a single line.
【输入样例】
5 30 10 25
15 30 25 40 35
【输出样例】
30
【解题思路】

【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, t, c, d, ans; // n: 物品数量,t: 阈值
// c: 第一种花费,d: 第二种花费
// ans: 总花费
signed main()
{
cin >> n >> t >> c >> d; // 读入物品数量、阈值和两种花费
for (int i = 1; i <= n; i++) // 遍历所有物品
{
int w;
cin >> w; // 读入当前物品的值
if (w >= t) // 如果当前物品的值大于等于阈值
{
ans += min(c, d); // 累加两种花费中较小的一个
}
}
cout << ans << endl; // 输出总花费
return 0;
}
【运行结果】
5 30 10 25
15 30 25 40 35
30
C - Team Formation
【题目来源】
AtCoder:C - Team Formation
【题目描述】
Takahashi is in charge of forming a team to participate in a programming contest.
高桥负责组建一支参加编程比赛的团队。
The club Takahashi belongs to has \(N\) members, and each member is identified by a number from \(1\) to \(N\). Whether member \(i\) has contest experience is represented by the value \(H_i\): \(H_i = 1\) means experienced, and \(H_i = 0\) means beginner. Additionally, member \(i\)'s programming skill is represented by the value \(P_i\).
高桥所在的俱乐部有 \(N\) 名成员,每个成员用编号 \(1\) 到 \(N\) 标识。成员 \(i\) 是否有比赛经验用值 \(H_i\) 表示:\(H_i = 1\) 表示有经验,\(H_i = 0\) 表示新手。此外,成员 \(i\) 的编程技能用值 \(P_i\) 表示。
Takahashi wants to select \(K\) members from the \(N\) members (without duplicates) to form a team for the contest. However, due to the contest rules, exactly \(M\) of the selected \(K\) members must be experienced, and exactly \(K - M\) must be beginners.
高桥想从这 \(N\) 名成员中选择 \(K\) 名成员(不允许重复)组成参赛队伍。然而,根据比赛规则,被选中的 \(K\) 名成员中恰好有 \(M\) 名必须有经验,恰好有 \(K - M\) 名必须是新手。
The team's overall strength is evaluated as the sum of the skill values \(P_i\) of the selected \(K\) members.
团队的整体实力评估为所选 \(K\) 名成员的技能值 \(P_i\) 之和。
Find the maximum possible overall strength of the team when members are selected to satisfy the conditions. If no valid selection exists, output \(-1\).
求在满足条件选择成员时,团队可能的最大整体实力。如果不存在有效的选择,则输出 \(-1\)。
【输入】
\(N\) \(K\) \(M\)
\(H_1\) \(P_1\)
\(H_2\) \(P_2\)
\(\vdots\)
\(H_N\) \(P_N\)
- The first line contains the total number of members \(N\), the number of members to select \(K\), and the required number of experienced members \(M\), separated by spaces.
- The following \(N\) lines, where the \(i\)-th line \((1 \leq i \leq N)\) contains \(H_i\) representing whether member \(i\) is experienced and their skill value \(P_i\), separated by a space.
【输出】
Output in one line the maximum overall team strength (sum of skill values) when members are selected to satisfy the conditions. If no valid selection exists, output \(-1\).
【输入样例】
5 3 1
1 100
0 80
0 90
1 50
0 70
【输出样例】
270
【解题思路】

【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int n, k, m, ans; // n: 总人数,k: 要选的人数,m: 第一类人(h=1)要选的数量
struct Node
{
int h, p; // h: 类别(0或1),p: 价值
}a[N];
// 自定义排序:先按h降序(h=1在前,h=0在后),再按p降序
bool cmp(Node x, Node y)
{
if (x.h != y.h)
{
return x.h > y.h;
}
return x.p > y.p;
}
signed main()
{
cin >> n >> k >> m; // 读入总人数、要选的人数、第一类人要选的数量
int cnt1 = 0, cnt0 = 0; // cnt1: 第一类人数量,cnt0: 第二类人数量
for (int i = 1; i <= n; i++)
{
cin >> a[i].h >> a[i].p; // 读入每个人的类别和价值
if (a[i].h == 1)
{
cnt1++;
}
else
{
cnt0++;
}
}
// 如果第一类人数不够m,或者第二类人数不够k-m,输出-1
if (cnt1 < m || cnt0 < k - m)
{
cout << -1 << endl;
return 0;
}
// 排序:h=1的在前,h=0的在后,每类内部按价值p降序
sort(a + 1, a + n + 1, cmp);
// 调试输出
// for (int i=1; i<=n; i++)
// cout << a[i].h << " " << a[i].p << endl;
// 取前m个h=1的人
for (int i = 1; i <= m; i++)
{
ans += a[i].p;
}
// cout << "ans " << ans << endl;
// 从cnt1+1开始(即第一个h=0的人),取k-m个人
for (int i = cnt1 + 1; i <= cnt1 + 1 + (k - m) - 1; i++)
{
ans += a[i].p;
}
cout << ans << endl; // 输出总价值
return 0;
}
【运行结果】
5 3 1
1 100
0 80
0 90
1 50
0 70
270
D - Escape from the Maze
【题目来源】
AtCoder:D - Escape from the Maze
【题目描述】
Takahashi is trapped in a maze inside an old building.
高桥被困在一座旧建筑内的迷宫中。
The building is represented as a grid with \(N\) rows and \(M\) columns. The cell at the \(i\)-th row from the top and the \(j\)-th column from the left is called cell \((i, j)\). The state of the \(i\)-th row of the grid is represented by the string \(S_i\): if the \(j\)-th character of \(S_i\) is #, then cell \((i, j)\) is a wall; if it is ., then cell \((i, j)\) is a passage.
该建筑表示为一个有 \(N\) 行 \(M\) 列的网格。从上数第 \(i\) 行、从左数第 \(j\) 列的单元格称为单元格 \((i, j)\)。网格第 \(i\) 行的状态用字符串 \(S_i\) 表示:如果 \(S_i\) 的第 \(j\) 个字符是 #,则单元格 \((i, j)\) 是墙壁;如果是 .,则单元格 \((i, j)\) 是通道。
Takahashi is currently at cell \((1, 1)\) and aims to reach the exit at cell \((N, M)\) in the bottom-right corner.
高桥目前位于单元格 \((1, 1)\),目标是到达右下角的出口单元格 \((N, M)\)。
In one operation, Takahashi can move from his current cell to one of the four adjacent cells (up, down, left, or right). However, he cannot move outside the grid. If the destination cell is a passage, he simply moves there. If the destination cell is a wall, he uses his hammer to destroy the wall, turning it into a passage, and then moves there. Each time a wall is destroyed, the destruction count increases by \(1\). A cell that has been destroyed and turned into a passage remains a passage thereafter. There is no limit on the number of times the hammer can be used, and there is no limit on the number of moves.
在一次操作中,高桥可以从当前单元格移动到四个相邻单元格(上、下、左、右)之一。但是,他不能移动到网格之外。如果目标单元格是通道,他直接移动到那里。如果目标单元格是墙壁,他会用锤子摧毁墙壁,将其变为通道,然后移动到那里。每次摧毁墙壁,破坏计数增加 \(1\)。被摧毁并变成通道的单元格此后保持为通道。锤子的使用次数没有限制,移动次数也没有限制。
Since Takahashi can destroy walls as many times as needed, he can always reach cell \((N, M)\). Find the minimum number of walls Takahashi needs to destroy to travel from cell \((1, 1)\) to cell \((N, M)\).
由于高桥可以根据需要多次摧毁墙壁,他总能到达单元格 \((N, M)\)。求高桥从单元格 \((1, 1)\) 到单元格 \((N, M)\) 所需摧毁的最小墙壁数量。
It is guaranteed that cell \((1, 1)\) and cell \((N, M)\) are always passages.
保证单元格 \((1, 1)\) 和单元格 \((N, M)\) 始终是通道。
【输入】
\(N\) \(M\)
\(S_1\)
\(S_2\)
\(\vdots\)
\(S_N\)
- The first line contains the number of rows \(N\) and the number of columns \(M\) of the grid, separated by a space.
- The \((1 + i)\)-th line \((1 \leq i \leq N)\) contains a string \(S_i\) of length \(M\) representing the state of the \(i\)-th row of the grid. The \(j\)-th character of \(S_i\) represents the state of cell \((i, j)\), where
#means a wall and.means a passage.
【输出】
Print in one line the minimum number of walls Takahashi needs to destroy to travel from cell \((1, 1)\) to cell \((N, M)\).
【输入样例】
3 5
...#.
.###.
...#.
【输出样例】
1
【解题思路】

【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 505;
int n, m; // n: 行数,m: 列数
char a[N][N]; // 地图
int dist[N][N]; // 从起点到每个位置的最小代价
struct Node
{
int x, y, cost; // 坐标和代价
};
// 重载大于运算符,用于优先队列(最小堆)
bool operator>(Node x, Node y)
{
return x.cost > y.cost;
}
int dx[4] = {-1, 1, 0, 0}; // 上下左右四个方向的行偏移
int dy[4] = {0, 0, -1, 1}; // 上下左右四个方向的列偏移
priority_queue<Node, vector<Node>, greater<Node> > pq; // 最小优先队列
int main()
{
cin >> n >> m; // 读入行数和列数
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> a[i][j]; // 读入地图
}
}
memset(dist, 0x3f, sizeof(dist)); // 初始化距离为无穷大
// 初始化起点
if (a[1][1] == '#')
{
dist[1][1] = 1; // 如果起点是'#',则代价为1
}
else
{
dist[1][1] = 0; // 否则代价为0
}
pq.push({1, 1, dist[1][1]}); // 将起点加入优先队列
while (!pq.empty())
{
Node t = pq.top(); // 取出当前最小代价节点
int x = t.x, y = t.y, cost = t.cost;
pq.pop();
for (int i = 0; i < 4; i++) // 遍历四个方向
{
int nx = x + dx[i], ny = y + dy[i]; // 相邻坐标
if (nx < 1 || nx > n || ny < 1 || ny > m) // 越界检查
{
continue;
}
// 如果通过当前节点到相邻节点的代价更小
if (dist[nx][ny] > cost + ((a[nx][ny] == '#') ? 1 : 0))
{
dist[nx][ny] = cost + ((a[nx][ny] == '#') ? 1 : 0); // 更新代价
pq.push({nx, ny, dist[nx][ny]}); // 将相邻节点加入队列
}
}
}
cout << dist[n][m] << endl; // 输出起点到终点的最小代价
return 0;
}
【运行结果】
3 5
...#.
.###.
...#.
1
E - Stone Crossing Game
【题目来源】
AtCoder:E - Stone Crossing Game
【题目描述】
Takahashi is attempting a stone jumping game to cross a river.
高桥正在尝试一个石头跳跃游戏来渡过一条河。
There are \(N\) stones lined up in a row in the river, numbered stone \(1\), stone \(2\), …, stone \(N\) from left to right. On stone \(i\) (\(1 \leq i \leq N\)), there are \(A_i\) coins placed.
河中有 \(N\) 块石头排成一行,从左到右编号为石头 \(1\)、石头 \(2\)、…、石头 \(N\)。在石头 \(i\)(\(1 ≤ i ≤ N\))上,放置有 \(A_i\) 枚硬币。
Takahashi initially stands on stone \(1\). When Takahashi stands on a stone, he collects all the coins on that stone (including the coins on stone \(1\) where he starts). Coins on stones he does not visit cannot be collected. The number of coins is not necessarily positive; it can be negative, in which case he is forced to collect them as well.
高桥初始时站在石头 \(1\) 上。当高桥站在一块石头上时,他会收集该石头上的所有硬币(包括他起始的石头 \(1\) 上的硬币)。他未访问的石头上的硬币无法收集。硬币的数量不一定为正数;它可以是负数,在这种情况下他也必须收集它们。
While Takahashi has not yet reached stone \(N\), he jumps to the right from his current stone. When he is currently on stone \(i\) (\(i < N\)), he can choose an integer \(d\) with \(1 \leq d \leq K\) and move to stone \(i+d\). However, the destination stone's number must be at most \(N\). That is, he can jump to any one of stone \(i+1\), stone \(i+2\), \(\ldots\), stone \(\min(i+K,\, N)\). Since movement is always to the right, he never stands on the same stone twice.
在高桥尚未到达石头 \(N\) 时,他从当前石头向右跳跃。当他当前在石头 \(i\)($i $$<$$ N$)上时,他可以选择一个整数 \(d\) 满足 \(1 ≤ d ≤ K\) 并移动到石头 \(i + d\)。但是,目标石头的编号必须不超过 \(N\)。也就是说,他可以跳到石头 \(i+1\)、石头 \(i+2\)、…、石头 \(min(i+K, N)\) 中的任意一块。由于移动总是向右,他从不会两次站在同一块石头上。
Takahashi must reach stone \(N\). The game ends when he reaches stone \(N\) and collects its coins. Since \(K \geq 1\) by the constraints, he can always reach stone \(N\) by advancing one step at a time from stone \(1\).
高桥必须到达石头 \(N\)。当他到达石头 \(N\) 并收集其硬币时游戏结束。根据约束条件 \(K ≥ 1\),他总是可以从石头 \(1\) 开始每次前进一步到达石头 \(N\)。
Find the maximum total number of coins Takahashi can collect starting from stone \(1\) and reaching stone \(N\).
求高桥从石头 \(1\) 出发到达石头 \(N\) 所能收集的最大硬币总数。
【输入】
\(N\) \(K\)
\(A_1\) \(A_2\) \(\ldots\) \(A_N\)
- The first line contains an integer \(N\) representing the number of stones and an integer \(K\) representing the maximum difference in stone numbers that can be covered in a single jump, separated by a space.
- The second line contains integers \(A_1, A_2, \ldots, A_N\) representing the number of coins placed on each stone, separated by spaces.
【输出】
Print in one line the maximum total number of coins that can be collected when moving from stone \(1\) to stone \(N\).
【解题思路】

【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
int n, k; // n: 数组长度,k: 最大跳跃步数
int a[N], dp[N]; // a: 原数组,dp: 动态规划数组
struct Node
{
int v, idx; // v: 值,idx: 索引
};
deque<Node> dq; // 单调队列(用于维护区间最大值)
signed main()
{
cin >> n >> k; // 读入数组长度和最大跳跃步数
for (int i = 1; i <= n; i++)
{
cin >> a[i]; // 读入数组元素
}
memset(dp, -0x3f, sizeof(dp)); // 初始化dp数组为极小值
dp[1] = a[1]; // 第一个位置的值
dq.push_back({dp[1], 1}); // 将第一个位置加入队列
for (int i = 2; i <= n; i++) // 从第二个位置开始计算
{
// cout << i << " " << dq.front().v << " " << dq.front().idx << endl;
// 删除队首超出范围(索引小于i-k)的元素
while (!dq.empty() && dq.front().idx < i - k)
{
dq.pop_front();
}
if (!dq.empty()) // 如果队列不为空
{
dp[i] = dq.front().v + a[i]; // dp[i] = 前k个位置中的最大值 + a[i]
}
// cout << "dp[i], dq.back " << dp[i] << " " << dq.back().v << endl;
// 维护队列单调递减性质
while (!dq.empty() && dq.back().v <= dp[i])
{
dq.pop_back();
}
// cout << "dp[i] i " << dp[i] << " " << i << endl;
dq.push_back({dp[i], i}); // 将当前位置加入队列
}
cout << dp[n]; // 输出最后一个位置的最大值
return 0;
}
【运行结果】
4 2
6 -1 -2 -1
4
浙公网安备 33010602011771号