ABC340

1|0E - Mancala 2

https://atcoder.jp/contests/abc340/tasks/abc340_e

按照题意模拟区间加和即可,但不能直接差分,因为下一次发放球又要使用新的球数,所以需要用到数据结构。

  • 线段树做法

    • 比较无脑,就用一颗lazytagSegmentTree实现区间加,单点查。
    template<class Info, class Tag> struct LazySegmentTree { int n; std::vector<Info> info; std::vector<Tag> tag; LazySegmentTree() : n(0) {} LazySegmentTree(int n_, Info v_ = Info()) { init(n_, v_); } template<class T> LazySegmentTree(std::vector<T> init_) { init(init_); } void init(int n_, Info v_ = Info()) { init(std::vector(n_, v_)); } template<class T> void init(std::vector<T> init_) { n = init_.size(); info.assign(4 << std::__lg(n), Info()); tag.assign(4 << std::__lg(n), Tag()); std::function<void(int, int, int)> build = [&](int p, int l, int r) { if (r - l == 1) { info[p] = init_[l]; return; } int m = (l + r) / 2; build(2 * p, l, m); build(2 * p + 1, m, r); pull(p); }; build(1, 0, n); } void pull(int p) { info[p] = info[2 * p] + info[2 * p + 1]; } void apply(int p, const Tag &v) { info[p].apply(v); tag[p].apply(v); } void push(int p) { apply(2 * p, tag[p]); apply(2 * p + 1, tag[p]); tag[p] = Tag(); } void modify(int p, int l, int r, int x, const Info &v) { if (r - l == 1) { info[p] = v; return; } int m = (l + r) / 2; push(p); if (x < m) { modify(2 * p, l, m, x, v); } else { modify(2 * p + 1, m, r, x, v); } pull(p); } void modify(int p, const Info &v) { modify(1, 0, n, p, v); } Info rangeQuery(int p, int l, int r, int x, int y) { if (l >= y || r <= x) { return Info(); } if (l >= x && r <= y) { return info[p]; } int m = (l + r) / 2; push(p); return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y); } Info rangeQuery(int l, int r) { return rangeQuery(1, 0, n, l, r); } void rangeApply(int p, int l, int r, int x, int y, const Tag &v) { if (l >= y || r <= x) { return; } if (l >= x && r <= y) { apply(p, v); return; } int m = (l + r) / 2; push(p); rangeApply(2 * p, l, m, x, y, v); rangeApply(2 * p + 1, m, r, x, y, v); pull(p); } void rangeApply(int l, int r, const Tag &v) { return rangeApply(1, 0, n, l, r, v); } }; struct Tag { i64 add = 0; void apply(Tag t) { add += t.add; } }; struct Info { i64 x = 0; int r, l; Info(){} Info(i64 _x, int l, int r):x(_x), l(l), r(r){} void apply(Tag t) { x += t.add * (r - l); } }; Info operator+(Info a, Info b) { return {a.x + b.x, a.l, b.r}; } signed main() { std::cin.tie(nullptr)->sync_with_stdio(false); int n, m; std::cin >> n >> m; std::vector<Info> a(n); for (int i = 0; i < n; i++) { std::cin >> a[i].x; a[i].l = i; a[i].r = i + 1; } LazySegmentTree<Info, Tag> T(a); for (int i = 0, x; i < m; i++) { std::cin >> x; i64 now = T.rangeQuery(x, x + 1).x; T.modify(x, {0, x, x + 1});//先把原来的位置清空 T.rangeApply(0, n, {now / n});//平均发放n轮 int y = x + (now % n); if (y < n) { T.rangeApply(x + 1, y + 1, {1}); } else { T.rangeApply(x + 1, n, {1}); T.rangeApply(0, y - n + 1, {1}); } } for (int i = 0; i < n; i++) {std::cout << T.rangeQuery(i, i + 1).x << ' ';} std::cout << '\n'; return 0; }
  • 树状数组维护差分

    • 用BIT维护一个差分数组
      • 区间加直接用差分来解决
      • 单点查再利用树状数组快速查询区间和的性质,对差分数组快速求和。
template<class T> struct BIT { int n; std::vector<T> w; BIT(int n) : n(n), w(n + 1) {} void add(int x, T v) {for (; x <= n; x += x & -x) {w[x] += v;}} T ask(int x) {T ans = 0; for (; x; x -= x & -x) {ans += w[x];} return ans;} T ask(int l, int r) {return ask(r) - ask(l - 1);} }; signed main() { std::cin.tie(nullptr)->sync_with_stdio(false); int n, m; std::cin >> n >> m; std::vector<int> a(n); for (auto& x : a) {std::cin >> x;} BIT<i64> bitT(n + 1); for (int i = 0; i < n; i++) {//BIT维护差分数组,BITfrom1 bitT.add(i + 1, a[i]); bitT.add(i + 1 + 1, -a[i]); } for (int i = 0, x; i < m; i++) { std::cin >> x; ++x; i64 now = bitT.ask(x);//差分和出当前位置的球数量 bitT.add(x, -now); bitT.add(x + 1, now);//把当前的球移除 bitT.add(1, now / n);//先平均分配n圈 int y = x + now % n;//剩下最后一批分配完后的下标 if (y <= n) { bitT.add(x + 1, 1); bitT.add(y + 1, -1); } else { bitT.add(x + 1, 1); bitT.add(1, 1); bitT.add(y - n + 1, -1); } } for (int i = 1; i <= n; i++) {std::cout << bitT.ask(i) << ' ';} std::cout << '\n'; return 0; }

2|0F - S = 1

https://atcoder.jp/contests/abc340/tasks/abc340_f


顶点为 (0,0),(X,Y)(A,B) 的三角形的面积是 |AYBX|2 。因此我们可以认为,在给定整数 XY 的情况下,这个问题要求找到一对整数 (A,B) ,使得

|AYBX|=2.

我们将解释如何解决这个问题。在这里,我们设 g=gcd(X,Y) .(注: gcd(a,b) 被定义为 |a||b| 的最大公约数)。
如果 g3 或更大,那么答案就不存在,因为 AYBX 总是 g 的倍数。
如果 g=1,2 ,那么我们总是可以使用一种叫做扩展欧氏算法的算法来求解。扩展欧氏算法是这样一种算法:输入整数对 (a,b) ,在 O(logmin(|a|,|b|)) 时间内找到一个整数对 (x,y) ,使得 ax+by=±gcd(a,b) 。(这里,保证整数对 x,y 是满足 max(|x|,|y|)max(|a|,|b|) 的整数)。

(Y,X) 作为扩展欧几里得算法的输入,可以得到一对 (c,d) ,即

cYdX=±g

|c|,|d|1017 作为返回值。我们最初想要的是一对 (A,B) ,即 AYBX=±2 ,可以通过将 cd 乘以 2g 得到。这个 (A,B) 安全地满足 |A|,|B|1018

因此,问题已经解决。计算复杂度约为 O(logmin(X,Y)) ,足够快了。

i64 exgcd(i64 a, i64 b, i64 &x, i64 &y) { if (!b) { x = 1, y = 0; return a; } i64 g = exgcd(b, a % b, y, x); y -= a / b * x; return g; } signed main() { std::cin.tie(nullptr)->sync_with_stdio(false); i64 x, y;//给定整数x, y std::cin >> x >> y; i64 c{}, d{};//即exgcd的解 i64 g = exgcd(y, x, c, d); if (2 % g != 0) {std::cout << -1 << '\n';} else { c *= 2 / g; d *= -2 / g; std::cout << c << ' ' << d << '\n'; } return 0; }

__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/18210342.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示