AtCoder Beginner Contest 330
A - Counting Passes (abc330 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, l; cin >> n >> l; int ans = 0; while (n--) { int x; cin >> x; ans += (x >= l); } cout << ans << '\n'; return 0; }
B - Minimize Abs 1 (abc330 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, l, r; cin >> n >> l >> r; while (n--) { int a; cin >> a; if (a <= l) cout << l << ' '; else if (a >= r) cout << r << ' '; else cout << a << ' '; } return 0; }
C - Minimize Abs 2 (abc330 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 d; cin >> d; int up = 2e6; LL ans = 1e18; for (int i = 0; i <= up; ++i) { LL x = 1ll * i * i; LL y = abs(d - x); LL y1 = floor(sqrt(y)), y2 = ceil(sqrt(y)); ans = min({ans, abs(x + y1 * y1 - d), abs(x + y2 * y2 - d)}); } cout << ans << '\n'; return 0; }
D - Counting Ls (abc330 D)
题目大意
给定一个包含ox
的二维矩阵。问所有的满足下述条件的三元组下标数量。
- 这三个三元组对应的符号都是
o
。 - 恰有两个三元组同一行。
- 恰有两个三元组同一列。
解题思路
三元组组成的图形都是形如
oo oo o o o o oo oo
由此我们枚举转折点的o
,由这个o
组成的图形的数量就是 ,其中表示这个 o
所在行和列的o
的数量。累计所有的这些o
即是答案。
注意答案可能会超int
。
神奇的代码
#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<string> s(n); for (auto& i : s) { cin >> i; } vector<int> col(n), row(n); for (int i = 0; i < n; ++i) { row[i] = ranges::count(s[i], 'o'); for (int j = 0; j < n; ++j) col[i] += (s[j][i] == 'o'); } LL ans = 0; for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) { if (s[i][j] == 'o') { ans += 1ll * (row[i] - 1) * (col[j] - 1); } } cout << ans << '\n'; return 0; }
E - Mex and Update (abc330 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; map<int, int> cnt; vector<int> ini(n + 1); iota(ini.begin(), ini.end(), 0); set<int> mex(ini.begin(), ini.end()); vector<int> a(n); auto insert = [&](int i) { int x = a[i]; cnt[x]++; if (cnt[x] == 1) mex.erase(x); }; auto remove = [&](int i) { int x = a[i]; cnt[x]--; if (cnt[x] == 0) mex.insert(x); }; for (int i = 0; i < n; ++i) { int x; cin >> x; a[i] = x; insert(i); } while (q--) { int pos, x; cin >> pos >> x; --pos; remove(pos); a[pos] = x; insert(pos); cout << *mex.begin() << '\n'; } return 0; }
F - Minimize Bounding Square (abc330 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; LL k; cin >> n >> k; vector<LL> x(n), y(n); for (int i = 0; i < n; ++i) cin >> x[i] >> y[i]; ranges::sort(x); ranges::sort(y); vector<LL> invx = x, invy = y; ranges::reverse(invx); ranges::reverse(invy); int l = -1, r = 1e9 + 1; auto ok = [&](int len, vector<LL>& p, int sign = 1) { LL sufsum = accumulate(p.begin(), p.end(), 0ll); LL presum = 0; LL minn = 1e18; int r = 0; for (int i = 0; i < n; ++i) { while (r < n && abs(p[r] - p[i]) <= len) { sufsum -= p[r]; ++r; } LL cnt = abs(p[i] * i - presum) + abs(sufsum - (p[i] + sign * len) * (n - r)); minn = min(cnt, minn); presum += p[i]; } return minn; }; auto check = [&](int len) { return min(ok(len, invx, -1), ok(len, x)) + min(ok(len, invy, -1), ok(len, y)) <= k; }; while (l + 1 < r) { int mid = (l + r) >> 1; if (check(mid)) r = mid; else l = mid; } cout << r << '\n'; return 0; }
G - Inversion Squared (abc330 G)
题目大意
给定一个数组,仅包含 或者 ,其中 中的数最多只出现一次。
计算满足以下条件的排列的逆序对的平方和。
- 。(即将 替换成其他数,使得形成一个排列)
解题思路
<++>
神奇的代码
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/17856223.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步