AtCoder Beginner Contest 330
A - Counting Passes
统计有几个值 ≥ L \ge L ≥L
时间复杂度 O ( N ) O(N) O(N)
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int N, L;
std::cin >> N >> L;
int ans = 0;
for (int i = 0; i < N; i++) {
int x;
std::cin >> x;
ans += x >= L;
}
std::cout << ans << "\n";
return 0;
}
B - Minimize Abs 1
要使得 ∣ X i − A i ∣ ≤ m i n ∣ Y − A i ∣ |X_i - A_i| \le min|Y - A_i| ∣Xi−Ai∣≤min∣Y−Ai∣,所以要使得不等式右边最小,Y的取值集合其实只有 L , R , A i {L,R,A_i} L,R,Ai,所以只需要比较一下哪个值使得不等式右边的结果更小就好了。
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int N, L, R;
std::cin >> N >> L >> R;
std::vector<int> A(N);
for (int i = 0; i < N; i++) {
std::cin >> A[i];
if (A[i] >= L && A[i] <= R) {
std::cout << A[i] << " ";
continue;
}
if (std::abs(L - A[i]) <= std::abs(R - A[i])) {
std::cout << L << " ";
} else {
std::cout << R << " ";
}
}
return 0;
}
C - Minimize Abs 2
显然就是一个枚举题。
枚举其中一个值,然后根据
D
D
D来求出另一个值,由于std::sqrt
强转之后会向下取整变为int
类型,因此每次需要枚举
y
,
y
+
1
y,y+1
y,y+1两个数。每次更新式子的最小值。
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
i64 D;
std::cin >> D;
i64 ans = 1E18;
for (i64 x = 0; ; x++) {
i64 v = x * x;
if (v > D) {
break;
}
i64 z = std::sqrt(D - v);
for (auto y : {z, z + 1}) {
ans = std::min(ans, std::abs(x * x + y * y - D));
}
}
std::cout << ans << "\n";
return 0;
}
D - Counting Ls
本题要求形如
oo
o
这样方案的个数,这些o不要求一定相连,那其实我们只需要枚举那个关键节点然后每行每列计算一下除去当前枚举节点还剩下多少字符就好了,那么每次对答案的贡献就是 ( r o w − 1 ) × ( c o l − 1 ) (row-1) \times (col-1) (row−1)×(col−1),然后将贡献累加起来即可。
时间复杂度 O ( N 2 ) O(N^{2}) O(N2)
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int N;
std::cin >> N;
std::vector<std::string> S(N);
for (int i = 0; i < N; i++) {
std::cin >> S[i];
}
std::vector<int> row(N), col(N);
for (int i = 0; i < N; i++) {
row[i] = std::count(S[i].begin(), S[i].end(), 'o');
}
for (int j = 0; j < N; j++) {
for (int i = 0; i < N; i++) {
col[j] += S[i][j] == 'o';
}
}
i64 ans = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (S[i][j] != 'o') {
continue;
}
i64 x = row[i] - 1, y = col[j] - 1;
ans += x * y;
}
}
std::cout << ans << "\n";
return 0;
}
E - Mex and Update
题目要求对于每次操作之后求出当前序列的mex。
数据范围 2 E 5 2E5 2E5,也就是说我们需要有 O ( n l o g n ) O(nlogn) O(nlogn)的做法解决上述问题。
注意到mex的性质:当前序列中最小的没有出现的非负整数,因此mex的值至多不会超过 N N N。
所以考虑用 s t d : : s e t std::set std::set来维护可能成为mex的数值,同时用 s t d : : m a p std::map std::map来维护某个数值的数量,发生变化时根据情况判断对 s t d : : s e t std::set std::set进行增删。
时间复杂度 O ( ( N + Q ) l o g N ) O((N + Q)logN) O((N+Q)logN)
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int N, Q;
std::cin >> N >> Q;
std::vector<int> A(N);
std::set<int> f;
std::map<int, int> cnt;
for (int i = 0; i < N + 5; i++) {
f.emplace(i);
}
for (int i = 0; i < N; i++) {
std::cin >> A[i];
cnt[A[i]] += 1;
if (cnt[A[i]] == 1) {
f.extract(A[i]);
}
}
while (Q--) {
int i, x;
std::cin >> i >> x;
i--;
if (--cnt[A[i]] == 0) {
f.emplace(A[i]);
}
A[i] = x;
if (++cnt[A[i]] == 1) {
f.extract(A[i]);
}
std::cout << *f.begin() << "\n";
}
return 0;
}
F - Minimize Bounding Square
题目是说要在规定操作步数之内最小化正方形边的值,容易想到二分答案。
至于check函数,我们一定是要将 X Y XY XY坐标分开来考虑的,然后来考虑这样一件事情:
如果在一条直线上有两点 a , b a,b a,b,想要在这条直线上再选择一个点 c c c,使得 d a c + d b c d_{ac}+d_{bc} dac+dbc的距离和最小,那么 c c c点一定在 a b ab ab之间。
再考虑本问题,计算 X X X坐标上的操作数时,先考虑 X X X坐标最外面的两个点,根据上面我们所考虑的,最外面两点到这个矩形的距离为
std::max(0, X[i] - X[j] - x)
,x为当前正在二分的边长。
Y Y Y坐标上的操作数也同理。
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int N;
i64 K;
std::cin >> N >> K;
std::vector<int> X(N), Y(N);
for (int i = 0; i < N; i++) {
std::cin >> X[i] >> Y[i];
}
std::sort(X.begin(), X.end());
std::sort(Y.begin(), Y.end());
auto check = [&](int x) {
i64 ans = 0;
for (int i = 0, j = N - 1; i <= j; i++, j--) {
ans += 1LL * std::max(0, X[j] - X[i] - x) + std::max(0, Y[j] - Y[i] - x);
}
// std::cerr << ans << "\n";
return ans <= K;
};
int lo = -1, hi = int(1E9) + 1;
while (hi - lo != 1) {
int m = (lo + hi) / 2;
if (check(m)) {
hi = m;
} else {
lo = m;
}
}
std::cout << hi << "\n";
return 0;
}