AtCoder Beginner Contest 348
A - Penalty Kick (abc348 A)
题目大意
给定,输出 ,长度为 。
解题思路
按题意模拟即可。
神奇的代码
n = int(input()) ans = "oox" * (n // 3) + "o" * (n % 3) print(ans)
B - Farthest Point (abc348 B)
题目大意
给定个点,对每个点,求出与其距离最远的点的下标。
解题思路
只有 ,对于每个点,花 遍历每个点最大化距离,时间复杂度为 。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin >> n; vector<array<int, 2>> p(n); for (auto& i : p) cin >> i[0] >> i[1]; for (int i = 0; i < n; ++i) { int dis = 0, ans = 0; for (int j = 0; j < n; ++j) { if (i == j) continue; int dis1 = (p[i][0] - p[j][0]) * (p[i][0] - p[j][0]) + (p[i][1] - p[j][1]) * (p[i][1] - p[j][1]); if (dis1 > dis) { dis = dis1; ans = j; } else if (dis1 == dis) { ans = min(ans, j); } } cout << ans + 1 << '\n'; } return 0; }
C - Colorful Beans (abc348 C)
题目大意
个豌豆,每个豌豆有美味值 和颜色值 。
豌豆之间只有颜色区别。
现在你会从一种颜色的豌豆里选一个豌豆出来。
最大化选出来的豌豆美味值的最小值。
解题思路
选定一个颜色,最坏情况就是选出了这个颜色中美味值最小的豌豆。
因此对每种颜色求出美味值最小的豌豆,然后所有颜色(决策)的美味值取个最大值即为答案。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin >> n; map<int, int> minn; for (int i = 0; i < n; i++) { int a, c; cin >> a >> c; if (minn.find(c) == minn.end()) { minn[c] = a; } else minn[c] = min(minn[c], a); } int ans = minn.begin()->second; for (auto& [c, a] : minn) { ans = max(ans, a); } cout << ans << '\n'; return 0; }
D - Medicines on Grid (abc348 D)
题目大意
二维网格,起点终点,有障碍物,有药,药的作用是将体力值变为。
初始起点,体力值为 ,问能否走到终点。
解题思路
考虑朴素搜索,记录状态,表示位于 ,当前体力值为 ,然后枚举四个方向搜索后继情况。
考虑总情况数,即 ,有点危险,可以加一些剪枝,比如设 表示到达 时的最大体力,采用 式的搜索即可。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int h, w; cin >> h >> w; vector<string> tu(h); for (auto& i : tu) cin >> i; vector<vector<int>> dp(h, vector<int>(w, -1)); vector<vector<int>> med(h, vector<int>(w, -1)); int n; cin >> n; for (int i = 0; i < n; i++) { int r, c, e; cin >> r >> c >> e; --r, --c; med[r][c] = e; } queue<pair<int, int>> q; vector<vector<int>> inq(h, vector<int>(w, 0)); for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if (tu[i][j] == 'S') { dp[i][j] = med[i][j]; q.push({i, j}); inq[i][j] = 1; } } } const array<int, 4> dx = {0, 0, 1, -1}; const array<int, 4> dy = {1, -1, 0, 0}; while (!q.empty()) { auto [x, y] = q.front(); q.pop(); inq[x][y] = 0; if (dp[x][y] <= 0) continue; for (int i = 0; i < 4; i++) { int nx = x + dx[i], ny = y + dy[i]; if (nx < 0 || nx >= h || ny < 0 || ny >= w || tu[nx][ny] == '#') continue; if (dp[nx][ny] < dp[x][y] - 1) { dp[nx][ny] = max(dp[x][y] - 1, med[nx][ny]); if (tu[nx][ny] == 'T') break; if (!inq[nx][ny]) { q.push({nx, ny}); inq[nx][ny] = 1; } } } } int ok = false; for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if (tu[i][j] == 'T' && dp[i][j] >= 0) { ok = true; break; } } } if (ok) { cout << "Yes\n"; } else { cout << "No\n"; } return 0; }
E - Minimize Sum of Distances (abc348 E)
题目大意
给定一棵树,点有点权,边权为。
定义 ,其中表示点 到点 的最小距离。
求的最小值。
解题思路
朴素求法即。枚举每个点,然后求一遍 ,然后计算,取最小值。枚举每个点耗时 ,计算 耗时 。
考虑优化 的计算。注意到是棵树,我们一般考虑先枚举根 ,计算 ,然后考虑枚举 的儿子 ,看看 能否从 得到。
枚举的点从 ,考虑的计算变化,只有变成 , 其中的子树的 ,其余的 的 。
即 ,这是我们已经算出来的。
当时,
代入得,
因此我们预处理表示以 为子树的 的和, 是所有的 的和,那不在 的子树的 的和可以表示成 。这样当 时, 就可以通过 在 内算出来了。
总的时间复杂度变为 。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin >> n; vector<vector<int>> edge(n); for (int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; u--; v--; edge[u].push_back(v); edge[v].push_back(u); } vector<int> c(n); for (auto& x : c) cin >> x; LL sum = accumulate(c.begin(), c.end(), 0ll); vector<LL> csum(n); LL f = 0; auto dfs = [&](auto self, int u, int fa, int deep) -> void { for (auto v : edge[u]) { if (v == fa) continue; self(self, v, u, deep + 1); csum[u] += csum[v]; } f += 1ll * c[u] * deep; csum[u] += c[u]; }; dfs(dfs, 0, 0, 0); LL ans = f; auto dfs2 = [&](auto self, int u, int fa) -> void { ans = min(ans, f); for (auto v : edge[u]) { if (v == fa) continue; f -= csum[v]; f += sum - csum[v]; self(self, v, u); f -= sum - csum[v]; f += csum[v]; } }; dfs2(dfs2, 0, 0); cout << ans << '\n'; return 0; }
F - Oddly Similar (abc348 F)
题目大意
给定个序列,长度为,问俩俩序列相似的对数。
俩序列相似,说明有奇数个位置,其数相同。
解题思路
考虑朴素做法,枚举两个序列,然后枚举下标,记录数相同的个数,其时间复杂度是。判断数相同如果不用 的话,在 下能跑过(吸氧太猛了。
n3方过2e3
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, m; cin >> n >> m; vector<vector<int>> a(n, vector<int>(m, 0)); for (auto& x : a) for (auto& y : x) cin >> y; int ans = 0; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { int sum = 0; for (int k = 0; k < m; k++) { sum ^= (a[i][k] == a[j][k]); } ans += sum; } } cout << ans << '\n'; return 0; }
朴素做法是,分别是枚举(一行),枚举 (另一行),再枚举 (列)。考虑对其中一个因素优化。经过尝试,我们可以对枚举优化。
其实是非常接近 的,一般是可以采用 优化,总复杂度可以除以 。
我们记表示第 列值为 的那些行的情况,即一个 , 表示第行 第列的值为, 则不为 。
枚举一行 ,然后枚举一列 ,我们将所有的 (这些都是 )异或起来,最后得到的就是第 行与其余行的相似度情况(同下标数相等的个数的奇偶性),统计其为 的个数即为 相似的 的数量。注意要把 的情况去掉。
时间复杂度是
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, m; cin >> n >> m; vector<vector<int>> a(n, vector<int>(m)); vector<vector<bitset<2000>>> cnt(m, vector<bitset<2000>>(1000)); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> a[i][j]; --a[i][j]; cnt[j][a[i][j]][i] = 1; } } int ans = 0; for (int i = 0; i < n; i++) { bitset<2000> s{}; for (int j = 0; j < m; j++) { s ^= cnt[j][a[i][j]]; } s[i] = 0; ans += s.count(); } ans /= 2; cout << ans << '\n'; return 0; }
G - Max (Sum - Max) (abc348 G)
题目大意
给定长度为的数组 ,对 ,求解以下答案。
选择个下标,使得 最大。
解题思路
<++>
神奇的代码
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话