AtCoder Beginner Contest 340
A - Arithmetic Progression (abc340 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 a, b, d; cin >> a >> b >> d; while (a <= b) { cout << a << ' '; a += d; } cout << '\n'; return 0; }
B - Append (abc340 B)
题目大意
依次进行次操作,分两种。
1 x
,将x
放到数组的末尾。2 k
,输出数组的倒数第 项。
解题思路
用vector
模拟即可,操作2
可快速寻址访问。
神奇的代码
#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 q; cin >> q; vector<int> a; while (q--) { int op; cin >> op; if (op == 1) { int x; cin >> x; a.push_back(x); } else { int k; cin >> k; cout << a[a.size() - k] << '\n'; } } return 0; }
C - Divide and Divide (abc340 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; cin >> n; set<LL> team; map<LL, LL> cnt; cnt[n] = 1; team.insert(n); LL ans = 0; while (!team.empty()) { LL u = *team.rbegin(); if (u == 1) break; team.erase(u); if (cnt[u] > 0) { ans += u * cnt[u]; team.insert(u / 2); cnt[u / 2] += cnt[u]; team.insert(u - u / 2); cnt[u - u / 2] += cnt[u]; cnt[u] = 0; } } cout << ans << '\n'; return 0; }
D - Super Takahashi Bros. (abc340 D)
题目大意
个关卡,初始只能打第一关卡。
对于第 关卡,可以花 代价解锁第 关卡,或花 代价解锁第 关卡。
问解锁第 关卡的最小代价。
解题思路
虽然说是解锁,但很显然打的下一关肯定是刚刚解锁的关卡。
根据上述解锁关系建一张图,边权就是解锁代价,原问题就是问点到点 的最短距离,跑一遍 dijkstra
即可。
神奇的代码
#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<vector<array<int, 2>>> edge(n); for (int i = 0; i < n - 1; ++i) { int a, b, d; cin >> a >> b >> d; --d; edge[i].push_back({i + 1, a}); edge[i].push_back({d, b}); } priority_queue<array<LL, 2>, vector<array<LL, 2>>, greater<array<LL, 2>>> pq; vector<LL> dis(n, 1e18); dis[0] = 0; pq.push({0, 0}); while (!pq.empty()) { auto [d, u] = pq.top(); pq.pop(); if (d > dis[u]) continue; for (auto [v, w] : edge[u]) { if (dis[v] > dis[u] + w) { dis[v] = dis[u] + w; pq.push({dis[v], v}); } } } cout << dis[n - 1] << endl; return 0; }
E - Mancala 2 (abc340 E)
题目大意
个盒子,第 个盒子有 个球。
依次进行以下 次操作:
- 第 次操作,将第 个盒子的所有球均分,多余的球从第个盒子依次放一个。
问最后每个盒子的球数量。
解题思路
朴素做法为,考虑优化每次操作的复杂度。
注意到均分
和放一个
都是区间加法,用线段树维护即可,时间复杂度是。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; const int N = 5e5 + 10; class segment { #define lson (root << 1) #define rson (root << 1 | 1) public: LL sum[N << 2]; LL lazy[N << 2]; void build(int root, int l, int r, vector<int>& a) { if (l == r) { sum[root] = a[l - 1]; lazy[root] = 0; return; } int mid = (l + r) >> 1; build(lson, l, mid, a); build(rson, mid + 1, r, a); lazy[root] = 0; } void pushdown(int root) { if (lazy[root]) { sum[lson] += lazy[root]; sum[rson] += lazy[root]; lazy[lson] += lazy[root]; lazy[rson] += lazy[root]; lazy[root] = 0; } } void update(int root, int l, int r, int L, int R, LL val) { if (L <= l && r <= R) { sum[root] += val; lazy[root] += val; return; } pushdown(root); int mid = (l + r) >> 1; if (L <= mid) update(lson, l, mid, L, R, val); if (R > mid) update(rson, mid + 1, r, L, R, val); } LL query(int root, int l, int r, int pos) { if (l == r) { return sum[root]; } pushdown(root); int mid = (l + r) >> 1; if (pos <= mid) return query(lson, l, mid, pos); else return query(rson, mid + 1, r, pos); } } sg; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, m; cin >> n >> m; vector<int> a(n); for (auto& i : a) cin >> i; sg.build(1, 1, n, a); for (int i = 0; i < m; ++i) { int b; cin >> b; ++b; LL cnt = sg.query(1, 1, n, b); sg.update(1, 1, n, b, b, -cnt); LL div = cnt / n; if (div) sg.update(1, 1, n, 1, n, div); LL mo = cnt % n; if (mo) { if (b + mo <= n) { sg.update(1, 1, n, b + 1, b + mo, 1); } else { sg.update(1, 1, n, b + 1, n, 1); sg.update(1, 1, n, 1, mo - (n - b), 1); } } } for (int i = 1; i <= n; ++i) { cout << sg.query(1, 1, n, i) << " \n"[i == n]; } return 0; }
F - S = 1 (abc340 F)
题目大意
给定点,求一整数点 ,使得 形成的三角形的面积为。
解题思路
考虑将 作为三角形的底,高的长度 需满足
即将直线 平移一下,距离其为的直线即为 所处的位置。
直线 的直线方程为
根据两平行直线的方程,得所处的直线为 。
根据俩平行直线距离公式,得其距离为,其为三角形的高 ,代入上述公式得 。
因此得到了 所处的直线方程为 以及 。
现在的问题就是找到一组整数解,满足上述方程。
注意到上述即为一个不定方程,用扩展欧几里德
解得即可。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; template <typename T> T extgcd(T a, T b, T& x, T& y) { if (a == 0) { x = 0; y = 1; return b; } T p = b / a; T g = extgcd(b - p * a, a, y, x); x -= p * y; return g; } int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); LL a, b; cin >> a >> b; auto ok = [](LL a, LL b) { LL x, y; LL d = extgcd(b, a, x, y); if (2 % d != 0) { return false; } cout << x * 2 / d << ' ' << y * 2 / d << '\n'; return true; }; if (!ok(-a, b) && !ok(a, -b)) cout << "-1\n"; return 0; }
G - Leaf Color (abc340 G)
题目大意
给定一棵树,点有颜色。
问子树的数量,其叶子颜色相同。
解题思路
<++>
神奇的代码
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/18013072
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
2020-02-10 Codeforces Round #618 (Div. 2)