AtCoder Beginner Contest 341
A - Print 341 (abc341 A)
题目大意
给定,输出 个 和 个 交替的字符串。
解题思路
循环输出即可。
神奇的代码
n = input() s = "10" * int(n) + "1" print(s)
B - Foreign Exchange (abc341 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<LL> a(n); for (auto& x : a) cin >> x; for (int i = 0; i < n - 1; ++i) { int x, y; cin >> x >> y; a[i + 1] += a[i] / x * y; } cout << a[n - 1] << '\n'; return 0; }
C - Takahashi Gets Lost (abc341 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 h, w, n; cin >> h >> w >> n; string t; cin >> t; vector<string> s(h); for (auto& i : s) cin >> i; int ans = 0; auto land = [&](int x, int y) { return 0 <= x && x < h && 0 <= y && y < w && s[x][y] != '#'; }; auto ok = [&](int x, int y) { if (!land(x, y)) return false; int nx, ny; for (auto& i : t) { if (i == 'L') { nx = x; ny = y - 1; } else if (i == 'R') { nx = x; ny = y + 1; } else if (i == 'U') { nx = x - 1; ny = y; } else if (i == 'D') { nx = x + 1; ny = y; } if (!land(nx, ny)) return false; x = nx; y = ny; } return true; }; for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { if (ok(i, j)) ++ans; } } cout << ans << '\n'; return 0; }
D - Only one of two (abc341 D)
题目大意
给定,问从只被n或m整除
的数中找出第 小的数,
解题思路
为方便考虑,可先简化问题,即假设互质。
注意到我们找出来的数是形如 或 , 我们考虑枚举这个。
显然枚举出的与其是第几个数
具有单调性,因此我们可以二分
枚举这个 。
先考虑的形式,我们要判断 是第几小的数。
注意到只被n或m整除
的数都是形如的。
在形如类别的数中,的排名是 ,其中 是的 的数量,其中。有多少呢?因为上述假设了互质,那么当且仅当 ,即。
在形如类别的数中,的排名是 ,其中 是的 的数量,其中有多少呢?因为上述假设了互质,那么当且仅当 ,即。
上述的除法均为整除。
那最终的排名就是两类别中排名的相加,即为。与 比较,就可以得知该 是偏大了还是偏小了,可以二分了。
上述是假设了 互质,而如果不互质时,会变得就只有 和 。假设 。考虑 如何算。
指 的 的数量,由于 与 互质,那其数量就等价于 的 的数量。 即
同理也可以求的
如此就可以二分求出第小的数了。
神奇的代码
#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; LL k; cin >> n >> m >> k; if (n > m) swap(n, m); int gg = gcd(n, m); LL ans = -1; auto calc = [&](LL n, LL m, __int128 a) { __int128 ldi = n / gg; __int128 rdi = m / gg; __int128 lcnt = a; __int128 rcnt = a * n / m; __int128 cnt = lcnt - (lcnt / rdi) + rcnt - (rcnt / ldi); return cnt; }; auto solve = [&](int n, int m) { __int128 l = 0, r = 1e18; while (l + 1 < r) { __int128 mid = (l + r) / 2; __int128 rank = calc(n, m, mid); if (rank >= k) r = mid; else l = mid; } if (calc(n, m, r) == k && r * n % m != 0) { ans = r * n; } }; solve(n, m); solve(m, n); cout << ans << '\n'; return 0; }
E - Alternating String (abc341 E)
题目大意
给定一个串,进行以下两种操作:
1 l r
,将的 翻转2 l r
,问是否是交替的。
解题思路
一个串是交替的,就是每一位与下一位的值都不同。
考虑数组 ,如果,那说明 是 交替的。
注意到操作一对该数组的影响仅仅是两个单点修改,而操作二是一个区间查询,用树状数组或线段树维护数组即可。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; // starting from 0 template <typename T> class fenwick { public: vector<T> fenw; int n; fenwick(int _n) : n(_n) { fenw.resize(n); } void modify(int x, T v) { while (x < n) { fenw[x] += v; x |= (x + 1); } } T get(int x) { T v{}; while (x >= 0) { v += fenw[x]; x = (x & (x + 1)) - 1; } return v; } T sum(int l, int r) { T tot = get(r); if (l != 0) { tot -= get(l - 1); } return tot; } }; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, q; cin >> n >> q; string s; cin >> s; fenwick<int> sum(n - 1); for (int i = 0; i < n - 1; ++i) { sum.modify(i, s[i] != s[i + 1]); } while (q--) { int op; cin >> op; if (op == 1) { int l, r; cin >> l >> r; --l, --r; if (l != 0) { sum.modify(l - 1, sum.sum(l - 1, l - 1) == 1 ? -1 : 1); } if (r != n - 1) { sum.modify(r, sum.sum(r, r) == 1 ? -1 : 1); } } else { int l, r; cin >> l >> r; --l, --r; if (sum.sum(l, r - 1) == r - l) cout << "Yes" << '\n'; else cout << "No" << '\n'; } } return 0; }
F - Breakdown (abc341 F)
题目大意
给定一张无向图,点有点权。一开始有些点有一些碎片。
问进行的操作的最大次数。
操作为,选择一个有碎片的点,拿走碎片,并从其邻居中选择一些点,满足,在每一个点放一个碎片。
解题思路
注意到操作里,碎片总是往点权小的点跑,这里有个方向性。我们可以先求权值小的点,那考虑权值大的点时,其考虑放置碎片的点的答案都求出来了,因此可以求出该点的答案。考虑。
按点权小到大的顺序求解,假设表示点有一个碎片带来的最大操作次数,那考虑求解当前点时,就是考虑其 的所有 选哪些 ,其 最大,且 ,其中这个 已经求出来了。
注意到上述的问题就是一个背包问题,因此就按照点权小到大的顺序求解 个 背包问题即可。
最后答案就是。
考虑其时间复杂度,每次 背包的复杂度是 ,乍一看以为是 ,但考虑到每次 背包中的 是邻居数量,所有的 背包的邻居数量的和其实是和 同数量级的,因此总的时间复杂度是 。
神奇的代码
#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>> edge(n); for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; --u, --v; edge[u].push_back(v); edge[v].push_back(u); } vector<int> w(n); for (auto& x : w) cin >> x; int up = *max_element(w.begin(), w.end()); vector<int> a(n); for (auto& x : a) cin >> x; vector<int> id(n); iota(id.begin(), id.end(), 0); sort(id.begin(), id.end(), [&](int x, int y) { return w[x] < w[y]; }); vector<int> cost(n); LL ans = 0; for (auto i : id) { vector<array<int, 2>> goods; for (auto j : edge[i]) { if (w[j] < w[i]) goods.push_back({w[j], cost[j]}); } if (goods.empty()) { cost[i] = 1; } else { vector<int> dp(w[i], 0); for (auto& [x, y] : goods) { for (int j = w[i] - 1; j >= x; j--) { dp[j] = max(dp[j], dp[j - x] + y); } } cost[i] = 1 + *max_element(dp.begin(), dp.end()); } ans += 1ll * a[i] * cost[i]; } cout << ans << '\n'; return 0; }
G - Highest Ratio (abc341 G)
题目大意
给定一个数组,对于每一个左端点,求右端点,其的平均值最大。
解题思路
记为前缀和,区间的平均值为。
从几何上看这个式子,它就是点和点 的斜率。
换句话说,二维平面上有一堆点 ,对于每个题意中的 ,就是要找 ,使得点 与点 的斜率最大。
一个朴素的想法就是从点 开始,花求一个凸包 (其实跟最朴素的暴力没区别),复杂度是。
反过来求凸包,即从最后一个点开始往前求凸包,保持斜率增大,当考虑到点 时,此时 下一个点的斜率是最大的,即此时就是对应的。
代码中判斜率变化是根据向量的旋转方向,用叉积来判方向。
神奇的代码
#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<LL> a(n + 1, 0); for (int i = 1; i <= n; ++i) cin >> a[i]; vector<LL> sum(n + 1); partial_sum(a.begin(), a.end(), sum.begin()); vector<pair<LL, LL>> team; auto convex = [&](const pair<LL, LL>& a, const pair<LL, LL>& b, const pair<LL, LL>& c) { return (c.first - a.first) * (b.second - a.second) - (c.second - a.second) * (b.first - a.first); }; vector<double> ans(n); for (int i = n; i >= 0; i--) { pair<LL, LL> p = {i, sum[i]}; while (team.size() >= 2 && convex(team[team.size() - 2], team.back(), p) >= 0) { team.pop_back(); } if (team.size() >= 1) { ans[p.first] = 1.0 * (p.second - team.back().second) / (p.first - team.back().first); } team.push_back(p); } cout << fixed << setprecision(8); for (int i = 0; i < n; ++i) { cout << ans[i] << '\n'; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!