AtCoder Beginner Contest 347
A - Divisible (abc347 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 n, k; cin >> n >> k; while (n--) { int a; cin >> a; if (a % k == 0) cout << a / k << ' '; } cout << '\n'; return 0; }
B - Substring (abc347 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 s; cin >> s; set<string> ans; for (int i = 0; i < s.size(); ++i) for (int j = i; j < s.size(); ++j) { ans.insert(s.substr(i, j - i + 1)); } cout << ans.size() << '\n'; return 0; }
C - Ideal Holidays (abc347 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); LL n, a, b; cin >> n >> a >> b; LL tot = a + b; vector<LL> d; for (int i = 0; i < n; i++) { int x; cin >> x; --x; x %= tot; d.push_back(x); d.push_back(x + tot); } ranges::sort(d); LL dis = numeric_limits<LL>::max(); for (int i = 0; i < n; i++) { dis = min(dis, d[i + n - 1] - d[i] + 1); } if (dis <= a) cout << "Yes" << endl; else cout << "No" << endl; return 0; }
D - Popcount and XOR (abc347 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 a, b; LL c; cin >> a >> b >> c; int aa = a, bb = b; auto popcount = [](LL x) { int ret = 0; while (x) { ret += x & 1; x >>= 1; } return ret; }; int cc = popcount(c); if (cc > a + b || ((a + b - cc) & 1)) { cout << -1 << '\n'; return 0; } int over = (a + b - cc) / 2; a -= over; b -= over; if (a < 0 || b < 0) { cout << -1 << '\n'; return 0; } LL A = 0, B = 0; for (int i = 0; i < 60; i++) { if (c & (1LL << i)) { if (a) { A |= 1LL << i; a--; } else if (b) { B |= 1LL << i; b--; } else { assert(0); } } else if (over) { A |= 1LL << i; B |= 1LL << i; over--; } } if (popcount(A) != aa || popcount(B) != bb) { cout << -1 << '\n'; return 0; } cout << A << ' ' << B << '\n'; return 0; }
E - Set Add Query (abc347 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, q; cin >> n >> q; vector<LL> presum; presum.push_back(0); set<int> s; vector<int> la(n, 0); vector<LL> ans(n, 0); for (int i = 1; i <= q; ++i) { int x; cin >> x; --x; if (s.count(x)) { ans[x] += presum[i - 1] - presum[la[x] - 1]; s.erase(x); } else { la[x] = i; s.insert(x); } presum.push_back(presum.back() + s.size()); } for (auto& i : s) { ans[i] += presum[q] - presum[la[i] - 1]; } for (auto& i : ans) { cout << i << ' '; } cout << '\n'; return 0; }
F - Non-overlapping Squares (abc347 F)
题目大意
给定一个的网格,问三个不重叠的 的网格覆盖,和的最大值。
解题思路
<++>
神奇的代码
G - Grid Coloring 2 (abc347 G)
题目大意
<++>
解题思路
<++>
神奇的代码
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具