AtCoder Beginner Contest 333
A - Three Threes (abc333 A)
题目大意
给定一个的数,输出这个数 次。
解题思路
模拟即可。
神奇的代码
#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 a; cin >> a; cout << string(a, '0' + a) << '\n'; return 0; }
B - Pentagon (abc333 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); string s1, s2; cin >> s1 >> s2; map<char, int> pos; for (int i = 0; i < 5; ++i) { pos['A' + i] = i; } auto dis = [&](char a, char b) { int dis = abs(pos[a] - pos[b]); return min(dis, abs(5 - dis)); }; if (dis(s1[0], s1[1]) == dis(s2[0], s2[1])) cout << "Yes" << '\n'; else cout << "No" << '\n'; return 0; }
C - Repunit Trio (abc333 C)
题目大意
定义一类数,其数位都是,即 。
问第 小的数,它可以表示成三个上述数的和。
解题思路
范围只有,直接枚举所有的组合情况,超过即 break
。
神奇的代码
#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; set<LL> ans; for (LL i = 1; 1; i = i * 10 + 1) { a.push_back(i); for (auto& j : a) for (auto& k : a) { ans.insert(i + j + k); } if (ans.size() >= n) break; } cout << vector<LL>(ans.begin(), ans.end())[n - 1] << '\n'; return 0; }
D - Erase Leaves (abc333 D)
题目大意
给定一棵树,每次删去一个叶子。
问把号点删除的最小操作数。
解题思路
考虑号点的所有儿子,当仅剩一个儿子时才可以删去 号点,那就保留儿子子树最大的那棵,其余全删除即可。
DFS
预处理下每个子树的大小和最大的儿子子树大小。
神奇的代码
#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> son(n), maxson(n); auto dfs = [&](auto self, int u, int fa) -> void { maxson[u] = son[u] = 1; for (auto& v : edge[u]) { if (v == fa) continue; self(self, v, u); maxson[u] = max(maxson[u], son[v]); son[u] += son[v]; } }; dfs(dfs, 0, 0); cout << son[0] - maxson[0] << '\n'; return 0; }
E - Takahashi Quest (abc333 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<array<int, 2>>> potion(n); vector<int> bag(n + 1); vector<int> action; bool ok = true; for (int i = 0; i < n; ++i) { int t, x; cin >> t >> x; --x; if (t == 1) { potion[x].push_back({int(action.size()), i}); action.push_back(0); } else { if (potion[x].empty()) { ok = false; break; } else { auto [potion_pos, pos] = potion[x].back(); potion[x].pop_back(); action[potion_pos] = 1; bag[pos]++; bag[i + 1]--; } } } int ans = bag[0]; for (int i = 1; i < n; ++i) { bag[i] += bag[i - 1]; ans = max(ans, bag[i]); } if (!ok) { cout << -1 << '\n'; } else { cout << ans << '\n'; for (auto& i : action) cout << i << ' '; cout << '\n'; } return 0; }
F - Bomb Game 2 (abc333 F)
题目大意
个人排队。每个时刻两个事件等概率发生:
- 第一个人出队
- 第一个人去该队伍的最后的位置。
最后剩下一个人。
问每个人存活到最后的概率。
解题思路
设表示有 个人时,第 个人存活的概率。根据概率的定义,有
很显然会发现有循环依赖,粗暴点可以直接高斯消元,但这题有 跑不动 。
那就把循环依赖去掉,去掉的方法就是把式子展开,然后移项即可。
求出了后, 都可以顺势算出来了。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; const int mo = 998244353; long long qpower(long long a, long long b) { long long qwq = 1; while (b) { if (b & 1) qwq = qwq * a % mo; a = a * a % mo; b >>= 1; } return qwq; } long long inv(long long x) { if (x < 0) x += mo; return qpower(x, mo - 2); } int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin >> n; vector<int> dp{0, 1}; int inv2 = inv(2); for (int i = 2; i <= n; ++i) { vector<int> dp2(n + 1); int p2 = 1; for (int j = i - 1; j >= 1; --j) { dp2[1] += 1ll * dp[i - j] * p2 % mo; if (dp2[1] >= mo) dp2[1] -= mo; p2 = 1ll * p2 * 2 % mo; } dp2[1] = 1ll * dp2[1] * inv(qpower(2, i) - 1) % mo; for (int j = 2; j <= i; ++j) { dp2[j] = 1ll * (dp[j - 1] + dp2[j - 1]) * inv2 % mo; } dp.swap(dp2); } for (int i = 1; i <= n; ++i) cout << dp[i] << " \n"[i == n]; return 0; }
G - Nearest Fraction (abc333 G)
题目大意
给定,找一对 ,使得 ,,且 最小。
解题思路
考虑到糖水加糖,越加越甜。对于初始范围 ,可以二分中间值(分子分母分别取均值),然后判断 在哪个范围内。然后继续二分。
但貌似 atcoder
的c++
的long double
的精度不够。
python
竟然有直接求解的库,偷了。
减了个1e-100
是想避免出现多个最小值。limit_denominator
是输出分母最小的那个,而原题要求最小。
神奇的代码
from fractions import Fraction fr = Fraction(input()) n = int(input()) print(*(fr - Fraction("1e-100")).limit_denominator(n).as_integer_ratio())
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/17919200.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步