AtCoder Beginner Contest 425 题解
比赛速览
● A - Sigma Cubes
● B - Find Permutation 2
● C - Rotate and Sum Query
● D - Ulam-Warburton Automaton
● E - Count Sequences 2
● F - Inserting Process
● G - Make it Increasing
A - Sigma Cubes
给定正整数 N,计算 ∑_{i=1}^N i³ 的值。
N 很小只有 100,直接使用 for 循环模拟计算即可。也可以使用公式:∑_{i=1}^N i³ = (N(N+1)/2)²。
对应课程知识点
本题的循环结构与数学计算对应极客程 《算法A-枚举与算法基础》 课程中的"枚举法"章节,涵盖基础循环与数学公式应用。
参考代码
#include <bits/stdc++.h>
using namespace std;int main() {int N;cin >> N;long long sum = 0;for (int i = 1; i <= N; i++) {sum += (long long)i * i * i;}cout << sum << endl;return 0;
}
B - Find Permutation 2
给定包含0和1N整数的序列A,判断是否存在1N的排列P满足A中的非零位置对应关系,并输出一个可行解。
首先检查A中非零元素是否有重复,若有则无解。然后创建包含所有1~N数字的集合,移除A中出现的非零数字。遍历A,如果位置为0则从集合中取最小数字填入,否则使用A中的数字。
对应课程知识点
本题的构造与贪心策略对应极客程 《算法B-贪心法与优化》 课程中的"贪心法"章节,涉及排列构造技术。
参考代码
#include <bits/stdc++.h>
using namespace std;int main() {int N;cin >> N;vector<int> A(N);vector<bool> used(N + 1, false);bool valid = true;for (int i = 0; i < N; i++) {cin >> A[i];if (A[i] != 0) {if (used[A[i]]) {valid = false;}used[A[i]] = true;}}if (!valid) {cout << "No" << endl;return 0;}set<int> available;for (int i = 1; i <= N; i++) {if (!used[i]) {available.insert(i);}}vector<int> P(N);for (int i = 0; i < N; i++) {if (A[i] != 0) {P[i] = A[i];} else {P[i] = *available.begin();available.erase(available.begin());}}cout << "Yes" << endl;for (int i = 0; i < N; i++) {cout << P[i] << (i == N - 1 ? "\n" : " ");}return 0;
}
C - Rotate and Sum Query
维护整数序列,支持旋转操作和区间和查询。
旋转操作相当于重新设定数列起点位置,维护start变量表示当前起点。对于区间和查询,根据当前start调整查询区间,使用前缀和数组快速计算。
对应课程知识点
本题的循环数组与前缀和技术对应极客程 《算法B-贪心法与优化》 课程中的"前缀和与子段和模型"章节。
参考代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;int main() {int N, Q;cin >> N >> Q;vector<ll> A(N);vector<ll> prefix(N + 1, 0);for (int i = 0; i < N; i++) {cin >> A[i];prefix[i + 1] = prefix[i] + A[i];}int start = 0;while (Q--) {int type;cin >> type;if (type == 1) {int c;cin >> c;start = (start + c) % N;} else {int l, r;cin >> l >> r;l--; r--;int actual_l = (start + l) % N;int actual_r = (start + r) % N;ll sum = 0;if (actual_l <= actual_r) {sum = prefix[actual_r + 1] - prefix[actual_l];} else {sum = (prefix[N] - prefix[actual_l]) + prefix[actual_r + 1];}cout << sum << endl;}}return 0;
}
D - Ulam-Warburton Automaton
网格自动机模拟,求K次操作后的黑色格子数量。
白色格子在第t轮被涂黑当且仅当它到最近黑色格子的曼哈顿距离恰好为t。使用多源BFS计算每个格子到最近黑色格子的距离,统计所有距离≤K的格子数量。
对应课程知识点
本题的多源BFS算法对应极客程 《算法C-深搜与宽搜》 课程中的"BFS-网格最短路"内容。
参考代码
#include <bits/stdc++.h>
using namespace std;int main() {int H, W, K;cin >> H >> W >> K;vector<string> grid(H);for (int i = 0; i < H; i++) {cin >> grid[i];}vector<vector<int>> dist(H, vector<int>(W, -1));queue<pair<int, int>> q;for (int i = 0; i < H; i++) {for (int j = 0; j < W; j++) {if (grid[i][j] == '#') {dist[i][j] = 0;q.push({i, j});}}}int dx[] = {1, -1, 0, 0};int dy[] = {0, 0, 1, -1};while (!q.empty()) {auto [x, y] = q.front();q.pop();for (int d = 0; d < 4; d++) {int nx = x + dx[d];int ny = y + dy[d];if (nx >= 0 && nx < H && ny >= 0 && ny < W && dist[nx][ny] == -1) {dist[nx][ny] = dist[x][y] + 1;q.push({nx, ny});}}}long long count = 0;for (int i = 0; i < H; i++) {for (int j = 0; j < W; j++) {if (dist[i][j] != -1 && dist[i][j] <= K) {count++;}}}cout << count << endl;return 0;
}
E - Count Sequences 2
计算满足元素出现次数限制的序列数量。
使用杨辉三角预处理组合数,多重组合数可以用组合数的乘积表示:C(n, a₁) × C(n-a₁, a₂) × … × C(n-a₁-…-a_{k-1}, a_k)。
对应课程知识点
本题的组合数学知识对应极客程 《算法D-入门级动态规划》 课程中的基础数学内容,为后续组合计数打下基础。
参考代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;vector<vector<ll>> precompute_combinations(int max_n, ll MOD) {vector<vector<ll>> C(max_n + 1, vector<ll>(max_n + 1, 0));for (int i = 0; i <= max_n; i++) {C[i][0] = C[i][i] = 1;for (int j = 1; j < i; j++) {C[i][j] = (C[i-1][j-1] + C[i-1][j]) % MOD;}}return C;
}int main() {ios_base::sync_with_stdio(false);cin.tie(NULL);int T;ll MOD;cin >> T >> MOD;int max_n = 100000;auto C = precompute_combinations(max_n, MOD);while (T--) {int N, M;cin >> N >> M;vector<int> A(N);int total = 0;for (int i = 0; i < N; i++) {cin >> A[i];total += A[i];}if (total > M) {cout << 0 << endl;continue;}ll result = 1;int remaining = M;for (int i = 0; i < N; i++) {result = result * C[remaining][A[i]] % MOD;remaining -= A[i];}cout << result << endl;}return 0;
}
F - Inserting Process
计算通过插入操作得到目标字符串的序列数量。
将问题转化为删除字符的方案数计数。使用动态规划,dp[l][r]表示子串S[l…r]的删除方案数。状态转移考虑删除第一个字符或最后一个字符,当两端字符相同时减去重复计算部分。
对应课程知识点
本题的动态规划思想对应极客程 《算法D-入门级动态规划》 课程中的"序列类DP"内容。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int MOD = 998244353;int main() {int N;string S;cin >> N >> S;vector<vector<long long>> dp(N, vector<long long>(N, 0));for (int i = 0; i < N; i++) {dp[i][i] = 1;}for (int len = 2; len <= N; len++) {for (int l = 0; l + len - 1 < N; l++) {int r = l + len - 1;dp[l][r] = (dp[l][r] + dp[l+1][r]) % MOD;dp[l][r] = (dp[l][r] + dp[l][r-1]) % MOD;if (S[l] == S[r]) {dp[l][r] = (dp[l][r] - dp[l+1][r-1] + MOD) % MOD;}}}cout << dp[0][N-1] << endl;return 0;
}
G - Make it Increasing
通过增加操作使序列至少有K个位置满足A[i] < A[i+1],求最小操作次数。
使用动态规划,dp[i][j]表示考虑前i个元素有j个上升位置时的最小操作次数。状态转移分别考虑是否在当前位置创建上升关系。
对应课程知识点
本题的动态规划优化对应极客程 《算法D-入门级动态规划》 课程中的"序列类DP"高级内容。
参考代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 1e18;int main() {int N, K;cin >> N >> K;vector<ll> A(N);for (int i = 0; i < N; i++) {cin >> A[i];}vector<vector<ll>> dp(N, vector<ll>(K + 1, INF));for (int j = 0; j <= K; j++) {dp[0][j] = 0;}for (int i = 1; i < N; i++) {for (int j = 0; j <= K; j++) {dp[i][j] = min(dp[i][j], dp[i-1][j]);if (j > 0) {ll cost = 0;if (A[i] <= A[i-1]) {cost = A[i-1] - A[i] + 1;}dp[i][j] = min(dp[i][j], dp[i-1][j-1] + cost);}}}ll ans = INF;for (int j = K; j <= K; j++) {ans = min(ans, dp[N-1][j]);}cout << ans << endl;return 0;
}
