2023-11-25 22:05阅读: 763评论: 1推荐: 0

AtCoder Beginner Contest 330

A - Counting Passes (abc330 A)

题目大意

给定n个学生的分数,以及及格分 x,问多少人及格了。

解题思路

依次判断即可。

神奇的代码
#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)

题目大意

回答n个问题,每个问题给定 a,l,r,问函数 f(x)=|xa|[l,r]的最小值。

解题思路

全定义域下,最小值显然在x=a取得。绝对值函数图像是V型。

现在限定在 [l,r],则分 al,ar,l<a<r三种情况分别讨论极值即可。即分别在x=l,x=r,x=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, 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)

题目大意

给定d,问函数 f(x,y)=|x2+y2d|的最小值。

解题思路

枚举x的取值,范围是[1,2e6],然后得 y2=abs(dxx),分别取 y1=y2,y2=y2,由于会有一正一负的情况(x2+y12d,x2+y22d),取min(f(x,y1),f(x,y2)),对所有 x取最小值即可。

神奇的代码
#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组成的图形的数量就是(row[i]1)×(col[j]1) ,其中row[i],col[j]表示这个 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)

题目大意

给定一个数组a,进行如下操作。

每次操作 令ai=x。然后输出 mex(a)

mex(a)表示数组a未出现的最小非负整数。

解题思路

考虑如何求出一个数组的mex,我们可以记 visit[i]表示数字 i的出现次数,那每次求 mex可以从小到大遍历该数组,找到第一个出现次数为0的下标即是答案。

但这复杂度可能会高达 O(n),考虑更快速的方法,我们可以用 set储存 visit数组中值为 0(未出现的数)下标,这样 set的最小值就是答案。

ai=x时,相当于把原来的 ai删掉,即 visit[ai],然后把 x加进来,即 visit[x]++,如果 visit[ai]变为 0,则说明 ai没有出现,将其插入到 set中。同时 visit[x]变为 1,说明 x出现了,从 set中删去。

这样就可以动态维护 mex值,其复杂度都是 O(log)

神奇的代码
#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)

题目大意

二维平面,点,可进行最多k次操作,每次操作将一个点上下左右移动一格。点可以重叠。

问进行操作后,能将所有点覆盖的正方形的边长的最小值。

解题思路

两个维度相互独立,我们可以分别考虑每个维度。

考虑一维情况下,如果我们固定覆盖的线段长度,会发现比较好做。

注意到如果边长越大,我们需要的移动次数越少,可行的可能性就越高,相反,边长越小,需要移动的次数越多,可行的可能性就越低。这里有一个单调性,因此我们可以二分最终的边长。

边长固定了,考虑到最优情况下,覆盖的线段必定有一端点上的点是从来没移动过的,因此我们可以枚举这个作为边界的点。然后计算需要移动的次数。

坐标从小到大考虑,可以用双指针维护移动次数(一个前缀坐标和与一个后缀坐标和)。注意需要分别枚举作为左端点的点和作为右端点的点。

两个维度分别取所需移动次数的最小值,其和不超过k则边长可行。

神奇的代码
#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)

题目大意

给定一个数组a,仅包含 1或者 [1,n],其中 [1,n]中的数最多只出现一次。

计算满足以下条件的排列的逆序对的平方和。

  • ai1=>pi=ai。(即将 1替换成其他数,使得形成一个排列)

解题思路

<++>

神奇的代码


本文作者:~Lanly~

本文链接:https://www.cnblogs.com/Lanly/p/17856223.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(763)  评论(1编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.