比赛速览
● 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;
}
557

被折叠的 条评论
为什么被折叠?



