比赛速览
● A - ABC -> AC
● B - Sum of Digits Sequence
● C - Bipartize
● D - The Simple Game
● E - Wind Cleaning
● F - Not Adjacent
● G - Takahashi’s Expectation 2
A - ABC -> AC
给定一个由大写英文字母组成的字符串 S,其中 S 的长度为奇数,删除 S 的中间字符后输出。
字符串基础操作,使用 string::erase 方法删除字符串中间的字符,计算中间位置索引为 n/2(0-based indexing)。
对应课程知识点
本题的字符串基础操作对应极客程 《算法A-枚举与算法基础》 课程中的"STL库"章节,涵盖字符串的基本处理方法。
参考代码
#include <bits/stdc++.h>
using namespace std;
int main() {
string s;
cin >> s;
int n = s.length();
int mid = n / 2;
s.erase(mid, 1);
cout << s << endl;
return 0;
}
B - Sum of Digits Sequence
定义 f(x) 为 x 的各位数字之和,给定初始值 X 和步数 K,计算序列 a₁ = X, a_{k+1} = f(a_k) 的第 K 项。
直接模拟递推过程,定义一个函数计算数字各位之和,循环 K-1 次计算序列的下一个值。
对应课程知识点
本题的模拟递推思想对应极客程 《算法A-枚举与算法基础》 课程中的"枚举法"章节,特别是数字处理的基本技巧。
参考代码
#include <bits/stdc++.h>
using namespace std;
int f(int x) {
int sum = 0;
while (x > 0) {
sum += x % 10;
x /= 10;
}
return sum;
}
int main() {
int X, K;
cin >> X >> K;
int a = X;
for (int i = 1; i < K; i++) {
a = f(a);
}
cout << a << endl;
return 0;
}
C - Bipartize
给定简单无向图,通过删除最少的边使图变为二分图。
由于 N ≤ 16,枚举所有可能的二分图划分方案,统计每种方案中需要删除的边数(连接同一部结点的边),取最小值。
对应课程知识点
本题的状态压缩枚举方法对应极客程 《算法A-枚举与算法基础》 课程中的"枚举法"章节,特别是状态压缩技术的应用。
参考代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int N, M;
cin >> N >> M;
vector<pair<int, int>> edges(M);
for (int i = 0; i < M; i++) {
cin >> edges[i].first >> edges[i].second;
edges[i].first--;
edges[i].second--;
}
int ans = M;
for (int mask = 0; mask < (1 << N); mask++) {
int remove_count = 0;
for (auto &e : edges) {
int u = e.first, v = e.second;
if (((mask >> u) & 1) == ((mask >> v) & 1)) {
remove_count++;
}
}
ans = min(ans, remove_count);
}
cout << ans << endl;
return 0;
}
D - The Simple Game
在有向图上进行 K 步移动游戏,Alice 和 Bob 轮流操作,最终根据棋子所在顶点字符决定胜负。
博弈论动态规划,dp[v][k] 表示在顶点 v 还需 k 步时的胜负状态,根据当前玩家分别采用存在性检查和全称检查进行状态转移。
对应课程知识点
本题的动态规划与博弈论思想对应极客程 《算法D-入门级动态规划》 课程中的"序列类DP"内容,为博弈类问题打下基础。
参考代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int N, M, K;
string C;
cin >> N >> M >> K >> C;
vector<vector<int>> graph(N);
for (int i = 0; i < M; i++) {
int u, v;
cin >> u >> v;
u--; v--;
graph[u].push_back(v);
}
vector<vector<bool>> dp(N, vector<bool>(K + 1, false));
for (int v = 0; v < N; v++) {
dp[v][0] = (C[v] == 'A');
}
for (int k = 1; k <= K; k++) {
for (int v = 0; v < N; v++) {
if (k % 2 == 1) {
dp[v][k] = false;
for (int u : graph[v]) {
if (dp[u][k-1]) {
dp[v][k] = true;
break;
}
}
} else {
dp[v][k] = true;
for (int u : graph[v]) {
if (!dp[u][k-1]) {
dp[v][k] = false;
break;
}
}
}
}
}
if (dp[0][K]) {
cout << "Alice" << endl;
} else {
cout << "Bob" << endl;
}
return 0;
}
E - Wind Cleaning
在网格上移动所有垃圾,要求垃圾不经过高桥位置且全部移出边界,求最小操作次数。
BFS状态搜索,将垃圾的边界矩形作为状态,通过四个方向的移动进行状态转移,搜索直到垃圾全部消失。
对应课程知识点
本题的BFS状态搜索对应极客程 《算法C-深搜与宽搜》 课程中的"BFS-网格最短路"内容,涉及状态空间的建模。
参考代码
#include <bits/stdc++.h>
using namespace std;
struct State {
int top, bottom, left, right;
bool operator==(const State& other) const {
return top == other.top && bottom == other.bottom &&
left == other.left && right == other.right;
}
};
namespace std {
template<> struct hash<State> {
size_t operator()(const State& s) const {
return s.top * 1000000 + s.bottom * 10000 + s.left * 100 + s.right;
}
};
}
int main() {
int H, W;
cin >> H >> W;
vector<string> grid(H);
int tx = -1, ty = -1;
vector<pair<int, int>> garbage;
for (int i = 0; i < H; i++) {
cin >> grid[i];
for (int j = 0; j < W; j++) {
if (grid[i][j] == 'T') {
tx = i; ty = j;
} else if (grid[i][j] == '#') {
garbage.push_back({i, j});
}
}
}
if (garbage.empty()) {
cout << 0 << endl;
return 0;
}
int top = H, bottom = -1, left = W, right = -1;
for (auto [i, j] : garbage) {
top = min(top, i);
bottom = max(bottom, i);
left = min(left, j);
right = max(right, j);
}
State initial = {top, bottom, left, right};
unordered_map<State, int> dist;
queue<State> q;
dist[initial] = 0;
q.push(initial);
int ans = -1;
while (!q.empty()) {
State curr = q.front();
q.pop();
if (curr.top > curr.bottom || curr.left > curr.right) {
ans = dist[curr];
break;
}
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
for (int d = 0; d < 4; d++) {
State next = curr;
if (d == 0) {
next.top++;
if (next.top > next.bottom) continue;
for (int j = next.left; j <= next.right; j++) {
if (next.top - 1 == tx && j == ty) goto skip;
}
} else if (d == 1) {
next.bottom--;
if (next.top > next.bottom) continue;
for (int j = next.left; j <= next.right; j++) {
if (next.bottom + 1 == tx && j == ty) goto skip;
}
} else if (d == 2) {
next.left++;
if (next.left > next.right) continue;
for (int i = next.top; i <= next.bottom; i++) {
if (i == tx && next.left - 1 == ty) goto skip;
}
} else {
next.right--;
if (next.left > next.right) continue;
for (int i = next.top; i <= next.bottom; i++) {
if (i == tx && next.right + 1 == ty) goto skip;
}
}
if (dist.find(next) == dist.end()) {
dist[next] = dist[curr] + 1;
q.push(next);
}
skip:;
}
}
cout << ans << endl;
return 0;
}
F - Not Adjacent
统计不相邻子序列中,和是 M 的倍数的子序列数量。
Meet-in-the-Middle技术,将序列分成两半,分别用动态规划统计各半的合法子序列,然后合并答案,注意前后两段的衔接约束。
对应课程知识点
本题的Meet-in-the-Middle技术对应极客程 《算法A-枚举与算法基础》 课程中的"枚举法"高级内容,涉及大规模问题的分治策略。
参考代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
int N, M;
cin >> N >> M;
vector<ll> A(N);
for (int i = 0; i < N; i++) {
cin >> A[i];
}
int half = N / 2;
vector<ll> first_half(A.begin(), A.begin() + half);
vector<ll> second_half(A.begin() + half, A.end());
vector<vector<ll>> dp1(half + 1, vector<ll>(M, 0));
dp1[0][0] = 1;
for (int i = 0; i < half; i++) {
vector<vector<ll>> new_dp = dp1;
for (int len = 0; len <= i; len++) {
for (int rem = 0; rem < M; rem++) {
if (dp1[len][rem] > 0) {
int new_rem = (rem + A[i]) % M;
new_dp[len + 1][new_rem] += dp1[len][rem];
}
}
}
dp1 = new_dp;
}
int second_size = N - half;
vector<vector<ll>> dp2(second_size + 1, vector<ll>(M, 0));
dp2[0][0] = 1;
for (int i = 0; i < second_size; i++) {
vector<vector<ll>> new_dp = dp2;
for (int len = 0; len <= i; len++) {
for (int rem = 0; rem < M; rem++) {
if (dp2[len][rem] > 0) {
int new_rem = (rem + A[half + i]) % M;
new_dp[len + 1][new_rem] += dp2[len][rem];
}
}
}
dp2 = new_dp;
}
ll ans = 0;
for (int len1 = 0; len1 <= half; len1++) {
for (int rem1 = 0; rem1 < M; rem1++) {
if (dp1[len1][rem1] == 0) continue;
for (int len2 = 0; len2 <= second_size; len2++) {
int needed_rem = (M - rem1) % M;
ans += dp1[len1][rem1] * dp2[len2][needed_rem];
}
}
}
ans--;
cout << ans << endl;
return 0;
}
G - Takahashi’s Expectation 2
动态维护礼物序列,支持添加礼物和查询:从初始mood开始,按规则处理所有礼物后的最终mood值。
使用平衡树维护礼物序列,对于每个查询,模拟处理过程:当礼物值小于等于当前mood时mood+2,否则mood-1。
对应课程知识点
本题的数据结构应用对应极客程 《算法B-贪心法与优化》 课程中的"优先队列与堆"内容,涉及动态数据维护。
参考代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int N, Q;
cin >> N >> Q;
vector<ll> A(N);
for (int i = 0; i < N; i++) {
cin >> A[i];
}
multiset<ll> gifts(A.begin(), A.end());
while (Q--) {
int t;
ll x;
cin >> t >> x;
if (t == 1) {
gifts.insert(x);
} else {
ll mood = x;
auto it = gifts.begin();
while (it != gifts.end()) {
if (*it <= mood) {
mood += 2;
it = gifts.erase(it);
} else {
mood -= 1;
++it;
}
}
cout << mood << endl;
}
}
return 0;
}
557

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



