2023-09-23 23:05阅读: 786评论: 5推荐: 0

AtCoder Beginner Contest 321

A - 321-like Checker (abc321 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);
string s;
cin >> s;
auto ok = [&]() {
for (int i = 0; i < s.size() - 1; ++i) {
if (s[i + 1] >= s[i])
return false;
}
return true;
};
if (ok())
cout << "Yes" << '\n';
else
cout << "No" << '\n';
return 0;
}


B - Cutoff (abc321 B)

题目大意

给定n1个数字,问最后一个数字最少是多少,使得你的分数不小于 x

数字在 [0,100]之间。分数是去掉最低最高后的和。

解题思路

因为范围不大,直接枚举最后一个数,找最大最小,然后求分数判断即可。

神奇的代码
#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, x;
cin >> n >> x;
vector<int> a(n);
for (int i = 0; i < n - 1; ++i)
cin >> a[i];
int ans = 0;
auto ok = [&]() {
auto tmp = a;
sort(tmp.begin(), tmp.end());
int sum =
accumulate(tmp.begin(), tmp.end(), 0) - tmp.front() - tmp.back();
return sum >= x;
};
for (; ans <= 100; ++ans) {
a[n - 1] = ans;
if (ok())
break;
}
if (ans == 101)
ans = -1;
cout << ans << '\n';
return 0;
}


C - 321-like Searcher (abc321 C)

题目大意

给定k,问321like的第 k小的数是多少。

321like就是第一题的定义,从高位到低位逐数字递减。

解题思路

最大的是9876543210,可以猜测数不多,直接搜索全部数出来,然后排序看第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 k;
cin >> k;
LL s = 0;
vector<LL> ans;
function<void(int)> dfs = [&](int x) {
s = s * 10 + x;
ans.push_back(s);
for (int i = x - 1; i >= 0; --i)
dfs(i);
s /= 10;
};
for (int i = 9; i >= 0; --i) {
dfs(i);
}
sort(ans.begin(), ans.end());
cout << ans[k] << '\n';
return 0;
}


D - Set Menu (abc321 D)

题目大意

给定两个数组a,b和一个数p,各从中取一个数x,y,得到贡献 min(x+y,p) 。问所有取法的贡献和。

解题思路

对数组b排序,枚举数组 a,那么小于 pab的贡献是 a+b,其余的贡献是 p,因此二分找到这个界限,分别计算这两类的贡献和即可,前者是个关于b的前缀和,后者就是一个数组bpa的数量的统计。时间复杂度是 O(nlogm)

也可以对a,b都排序,此时a枚举从大到小, 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, m;
LL p;
cin >> n >> m >> p;
vector<LL> a(n), b(m);
vector<LL> sumb(m);
for (auto& i : a)
cin >> i;
for (auto& i : b)
cin >> i;
sort(b.begin(), b.end());
partial_sum(b.begin(), b.end(), sumb.begin());
LL ans = 0;
for (auto& i : a) {
LL r = p - i;
auto cnt = lower_bound(b.begin(), b.end(), r) - b.begin();
ans += 1ll * i * cnt + (cnt ? sumb[cnt - 1] : 0) + 1ll * p * (m - cnt);
}
cout << ans << '\n';
return 0;
}


E - Complete Binary Tree (abc321 E)

题目大意

给定一棵完全二叉树,问与点x的距离为k的个数。

t组。

解题思路

示例图

考虑点5距离为 k的点都在哪。

首先在以该点的子树内,深度为 k的点有 2k(起始为0), 对应的标号都可以求出来,这样可以判断在n内的标号有多少个。

然后考虑该点的父亲的另一个节点(点4)的子树内,此时我们要求的深度是 2k2的点的个数。

然后考虑该点的父亲的父亲的另一个节点(点3)的子树内,此时我们要求的深度是2k3的点的个数。

不断往父亲考虑,因为每次往父亲走,点标号都会除以 2,最多 log次就考虑完了。

总的复杂度是 O(tlogn)

神奇的代码
#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 t;
cin >> t;
auto solve = [&](LL x, LL k, LL n) {
if (k < 0)
return 0ll;
if (k >= 64)
return 0ll;
__int128 num = (1ll << k), l = x;
l = (l << k);
__int128 r = l + num - 1;
if (l > n)
return 0ll;
LL ret = min(r, (__int128)n) - l + 1;
return ret;
};
while (t--) {
LL n, x, k;
cin >> n >> x >> k;
LL ans = 0;
if (k)
ans += solve(x, k, n);
while (x > 1 && k > 0) {
--k;
ans += solve((x ^ 1), k - 1, n);
x /= 2;
}
if (x && k == 0)
ans++;
cout << ans << '\n';
}
return 0;
}


F - #(subset sum = K) with Add and Erase (abc321 F)

题目大意

箱子,放球,拿球,球上有数,各不相同。

每次操作后,问里面球数和为k的方案数。

解题思路

不考虑拿走球的操作,每次放球,求方案数,就是一个经典的0/1背包。

dp[i]表示和为 j的方案数,考虑选不选这个球(其数字为x),则有 dp[i]=dp[i]+dp[ix]

现在拿走这个球,得从中剔除选了这个球的方案数。

dp2[i]表示不选该球,和为 i的方案数。由于 dp[i]的方案包括两部分:选了该球和没选该球的。只要减去选了该球的方案数,那就是没选该球的方案数。而选了该球的方案数,其实就是 dp2[ix],即选了这个球后,剩下的 ix就是由不选该球的方案数组成,这恰好是我们定义的 dp2[ix]的定义。

于是 dp2[i]=dp[i]dp2[ix]转移式即可。

时间复杂度是 O(qn)

这其实是最经典的退背包问题。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int mo = 998244353;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int q, k;
cin >> q >> k;
vector<int> dp(k + 1, 0);
dp[0] = 1;
while (q--) {
string op;
int x;
cin >> op >> x;
if (op[0] == '+') {
for (int i = k; i >= x; --i) {
dp[i] += dp[i - x];
if (dp[i] >= mo)
dp[i] -= mo;
}
} else {
vector<int> dp2(k + 1, 0);
for (int i = 0; i <= k; ++i) {
if (i < x) {
dp2[i] = dp[i];
} else {
dp2[i] = dp[i] - dp2[i - x];
if (dp2[i] < 0)
dp2[i] += mo;
}
}
dp.swap(dp2);
}
cout << dp[k] << '\n';
}
return 0;
}


G - Electric Circuit (abc321 G)

题目大意

给定n个部件和 m条线。部件有接口,有红蓝两色,数量都是m。一条线链接的两个接口必须不同颜色,但可以同个部件。

将部件视为点,线视为边,随机连线,问联通块的期望个数。

解题思路

<++>

神奇的代码


本文作者:~Lanly~

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

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

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