Educational Codeforces Round 23

1|0A. Treasure Hunt


#include <bits/stdc++.h> using namespace std; int read() { int x = 0, f = 1, ch = getchar(); while ((ch < '0' || ch > '9') && ch != '-') ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x * f; } int main(){ int a , b , c , d , x , y; cin >> a >> b >> c >> d >> x >> y; a = abs( a - c ) , b = abs( b - d ); if( a % x == 0 && b % y == 0 && (a / x)%2 == (b / y)%2 ) cout << "YES\n"; else cout << "NO\n"; return 0; }

2|0B. Makes And The Product


排个序,然后取最小的三个数,然后分类讨论一下就好了。

#include <bits/stdc++.h> using namespace std; #define int long long int read() { int x = 0, f = 1, ch = getchar(); while ((ch < '0' || ch > '9') && ch != '-') ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x * f; } int32_t main() { int n = read(); vector<int> a(n); map<int, int> cnt; for (auto &i: a) i = read(), cnt[i]++; sort(a.begin(), a.end()); int x = a[0], y = a[1], z = a[2]; if (x == y && y == z) { int m = cnt[x]; cout << m * (m - 1) * (m - 2) / 6; } else if (x == y && y != z) { int p = cnt[x], q = cnt[z]; cout << p * (p - 1) / 2 * q; } else if (x != y && y == z) { int p = cnt[x], q = cnt[z]; cout << p * q * (q - 1) / 2; } else cout << cnt[x] * cnt[y] * cnt[z]; return 0; }

3|0C. Really Big Numbers


定义x每一位的和是f(x),则求在[1,n]xf(x)s的个数。

首先如果a满足af(a)s,则a+1f(a+1)>=s一定满足。所以我们直接二分的找到最小的x即可

#include <bits/stdc++.h> using namespace std; #define int long long int read() { int x = 0, f = 1, ch = getchar(); while ((ch < '0' || ch > '9') && ch != '-') ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x * f; } int32_t main() { auto f = [](int x){ int ans = 0; while( x ) ans += x % 10 , x /= 10; return ans; }; int n , s; cin >> n >> s; int l = 1 , r = n , mid , ans = -1; while( l <= r ){ mid = ( l + r ) >> 1; if( mid - f(mid) >= s ) ans = mid , r = mid - 1; else l = mid + 1; } if( ans == -1 ) cout << 0 << "\n"; else cout << n - ans + 1; return 0; }

4|0D. Imbalanced Array


这题最朴素的想法是枚举区间,然后统计最值,复杂度O(N3).

很容易想到用ST表优化到O(N2).

这样的思路其实是枚举区间,我们其实可以换一个角度去思考,对于ai在哪些区间里面做最值。

以最大值为例,如果我们找到i做侧第一个比ai大的值al和右侧的第一个ar其实就是[l+1,r1]之间左右包含i的区间的最大值都是ai.

这样的话,用 ST表配合二分求出左右共四个端点即可,复杂度O(NlogN).

这里求最值的话也可利用单调栈的性质优化到O(N).

#include <bits/stdc++.h> using namespace std; #define int long long int read() { int x = 0, f = 1, ch = getchar(); while ((ch < '0' || ch > '9') && ch != '-') ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x * f; } int32_t main() { int n = read(); vector<int> a(n + 2); vector<int> maxL(n + 1), maxR(n + 1), minL(n + 1), minR(n + 1); for (int i = 1; i <= n; i++) a[i] = read(); a[0] = a[n + 1] = LLONG_MAX; // 左侧最大 stack<int> s; s.push(0); for (int i = 1; i <= n; i++) { while (a[i] >= a[s.top()]) s.pop(); maxL[i] = i - s.top(), s.push(i); } // 右侧最大 s = stack<int>(), s.push(n + 1); for (int i = n; i >= 1; i--) { while (a[i] > a[s.top()]) s.pop(); maxR[i] = s.top() - i, s.push(i); } // 左侧最小 a[0] = a[n + 1] = LLONG_MIN; s = stack<int>(), s.push(0); for (int i = 1; i <= n; i++) { while (a[i] <= a[s.top()]) s.pop(); minL[i] = i - s.top(), s.push(i); } // 右侧最小 s = stack<int>(), s.push(n + 1); for (int i = n; i >= 1; i--) { while (a[i] < a[s.top()]) s.pop(); minR[i] = s.top() - i, s.push(i); } int res = 0; for (int i = 1; i <= n; i++) res += (maxL[i] * maxR[i] - minL[i] * minR[i]) * a[i]; printf("%lld\n", res); return 0; }

5|0E. Choosing The Commander


用01Tire维护当前集合中的数,注意在插入的时候从二进制的高位开始插入。

对于查询操作,我们沿着pili的路径去遍历前缀,如果对于当前的节点向另一个方向走可以使得pxpi<li,就加上另一个子树的权值即可。

#include <bits/stdc++.h> using namespace std; typedef bitset<30> Num; class Tire { private: struct Node { int v, cnt, size, to0, to1; Node(int v = -1, int cnt = 0, int to0 = -1, int to1 = -1) : v(v), cnt(cnt), to0(to0), to1(to1) { size = 0; }; }; vector<Node> T; public: Tire() { T.push_back(Node()); } void insert(Num x) { vector<int> road; int pos = 0; for (int i = 29; i >= 0; i--) { if (x[i] == 0) { if (T[pos].to0 == -1) T[pos].to0 = T.size(), T.emplace_back(0); pos = T[pos].to0; } else { if (T[pos].to1 == -1) T[pos].to1 = T.size(), T.emplace_back(1); pos = T[pos].to1; } road.push_back(pos); } T[pos].cnt++; for (auto i: road) T[i].size++; } void del(Num x) { vector<int> road; int pos = 0; for (int i = 29; i >= 0; i--) { if (x[i] == 0) pos = T[pos].to0; else pos = T[pos].to1; road.push_back(pos); } T[pos].cnt--; for (auto i: road) T[i].size--; } int query(Num x, Num y) { int ans = 0, pos = 0; for (int i = 29, p; i >= 0; i--) { if (y[i] == 1) { if (x[i] == 0) p = T[pos].to0; else p = T[pos].to1; if (p != -1) ans += T[p].size; } if (x[i] ^ y[i] == 0) pos = T[pos].to0; else pos = T[pos].to1; if (pos == -1) break; } return ans; } }; int main() { ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); int q; cin >> q; Tire tire; for (int op, p, l; q; q--) { cin >> op >> p; if (op == 1) tire.insert(Num(p)); else if (op == 2)tire.del(Num(p)); else { cin >> l; cout << tire.query(Num(p), Num(l)) << "\n"; } } return 0; }

6|0F. MEX Queries


把这个题当做有一个大小为1018的数组,数组一开始全为 0,有三种操作,区间赋1、区间赋 0、区间取反,每次操作后询问最靠左的 0 的下标。

这样就会发现这是 ODT 的模板题,mex就是第一个值为 0 的区间的左端点。

#include <bits/stdc++.h> using namespace std; #define int long long int read() { int x = 0, f = 1, ch = getchar(); while ((ch < '0' || ch > '9') && ch != '-') ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x * f; } class ODT { private: struct Node { int l, r; mutable int val; Node(int l, int r = 0, int val = 0) : l(l), r(r), val(val) {}; bool operator<(Node b) const { return l < b.l; } int len() const { return r - l + 1; } }; const int len = 1e18; set<Node> s; public: ODT() { s.insert(Node(1, len, 0)); } auto split(int x) { if (x > len) return s.end(); auto it = --s.upper_bound(Node(x)); if (it->l == x) return it; int l = it->l, r = it->r, v = it->val; s.erase(it); s.insert(Node(l, x - 1, v)); return s.insert(Node(x, r, v)).first; } void assign(int l, int r, int v) { auto itr = split(r + 1), itl = split(l); s.erase(itl, itr); s.insert(Node(l, r, v)); } void invert(int l, int r) { auto itr = split(r + 1), itl = split(l); for (auto it = itl; it != itr; it++) it->val ^= 1; } int mex() { for (auto it: s) { if (it.val == 0) return it.l; } return len + 1; } }; int32_t main() { int q = read(); ODT odt; for( int op , l , r ; q ; q -- ){ op = read() , l = read() , r = read() ; if( op == 1 ) odt.assign( l , r , 1 ); else if( op == 2 ) odt.assign( l , r , 0 ); else odt.invert( l , r ); printf("%lld\n" , odt.mex() ); } return 0; }

__EOF__

本文作者PHarr
本文链接https://www.cnblogs.com/PHarr/p/17544947.html
关于博主:前OIer,SMUer
版权声明CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
posted @   PHarr  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· Apache Tomcat RCE漏洞复现(CVE-2025-24813)
点击右上角即可分享
微信分享提示