【湖北工业大学2025年ACM校赛(同步赛)】题解

比赛链接

A. 蚂蚁上树

题目大意

给定一棵 n n n 个结点的树,根结点为 1 1 1。每个 叶结点 都有一只蚂蚁,每过 1 1 1 秒钟,你可以选一些蚂蚁往其 父结点 走一步,但是要求任意两只蚂蚁都不能在同一个 非根结点 上。

问至少要多少时间,使得所有蚂蚁都走到 根节点

数据范围

  • 2 ≤ n ≤ 5 ⋅ 1 0 5 . 2 \leq n \leq 5 \cdot 10^5. 2n5105.

Solution

显然,根结点 1 1 1 的每个儿子都是独立的,所以下面考虑其中一个儿子 x x x

直觉上考虑,对于越深的结点,应该越迟到 x x x,所以我们可以将 x x x 下所有的叶子按照深度从小到大排序,初始化 d = 0 d = 0 d=0,接着顺序遍历这些结点,然后不断令 d = max ⁡ ( d + 1 , d e p i ) d = \max(d + 1, dep_i) d=max(d+1,depi),其中 d e p i dep_i depi 表示结点 i i i 的深度。

这表示,如果深度相同,需要等我往上走一步,再轮到你;否则你至少比我落后一步。

答案就是每个儿子 d d d 的最大值。

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

C++ Code

#include <bits/stdc++.h>int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int n;std::cin >> n;std::vector<std::vector<int>> adj(n);for (int i = 1; i < n; i++) {int u, v;std::cin >> u >> v;u--, v--;adj[u].push_back(v);adj[v].push_back(u);}std::vector<int> dep(n);std::vector<int> par(n, -1);std::vector<std::vector<int>> leaf(n);auto dfs = [&](auto &&self, int x, int bel) -> void {if (x != bel and adj[x].empty()) {leaf[bel].push_back(x);}for (int y: adj[x]) {adj[y].erase(std::ranges::find(adj[y], par[y] = x));dep[y] = dep[x] + 1;self(self, y, bel != 0 ? bel: y);}};dfs(dfs, 0, 0);if (std::ranges::max(dep) == 1) {std::cout << 1 << "\n";return 0;}int ans = 1;for (auto &l: leaf) {std::ranges::sort(l, [&](int x, int y) {return dep[x] < dep[y];});int res = 0;for (int x: l) {res = std::max(res + 1, dep[x]);}ans = std::max(ans, res);}std::cout << ans << "\n";return 0;
}

B. 奶龙大战贝利亚

题目大意

奶龙和贝利亚在玩一个游戏,给出一个 n × m n \times m n×m 的棋盘,棋盘上摆满了黑白棋。

每一轮玩家可以按顺序执行如下操作:

  • 选择其中一行,该行 至少 存在一个黑面朝上的棋子;
  • 从该行选择至少一个棋子,且选择的棋子中最左边的那个棋子必须为黑面朝上;
  • 将选择的棋子依次翻转(黑变白,白变黑)。

两人轮流依次进行操作,奶龙先手。

如果轮到某人时无法操作,则此人输掉了游戏。

给定起始盘面, W W W 表示该格棋子是白面朝上, B B B 表示该格棋子是黑面朝上。

奶龙想知道在两人都足够聪明的情况下,它是否有必胜方案。

数据范围

  • 1 ≤ n × m ≤ 1 0 6 . 1 \leq n \times m \leq 10^6. 1n×m106.

Solution

赛时是猜了三发猜出来的,证明的话可以直接看 官解

B B B 看作 1 1 1 W W W 看作 0 0 0,然后我们就有了 n n n 个长度均为 m m m 的二进制数。

那么结论就是: n n n 行的二进制数异或和不为 0 0 0,先手必胜

时间复杂度 O ( n m ) O(\rm{nm}) O(nm)

C++ Code

#include <bits/stdc++.h>int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int n, m;std::cin >> n >> m;auto s = std::string(m, '0');for (int i = 0; i < n; i++) {std::string g;std::cin >> g;for (int j = 0; j < m; j++) {if (g[j] == 'B') {s[j] ^= 1;}}}std::cout << (std::ranges::count(s, '1') > 0 ? "Yes\n": "No\n");return 0;
}

C. 我是奶龙

题目大意

给定 T T T 组数据,每组给定三个非负整数 n , m , k n, m, k n,m,k

对于每组 n , m , k n, m, k n,m,k,它表示:

  • 有一群奶龙变成了三种颜色,其中 n n n 条红奶龙, m m m 条蓝奶龙, k k k 条黄奶龙。当 两条不同颜色 的奶龙相遇时,它们会为了证明自己是真奶龙都会 变为第三种颜色,每个时刻只有一对奶龙相遇,问一段时间后,所有奶龙颜色是否可能相同?

数据范围

  • 1 ≤ T ≤ 1 0 5 , 1 \leq T \leq 10^5, 1T105,
  • 0 ≤ n , m , k ≤ 1 0 18 . 0 \leq n, m, k \leq 10^{18}. 0n,m,k1018.

Solution

算是个小数学题,我们一步步来推导。令 s = n + m + k s = n + m + k s=n+m+k

假设红奶龙( R R R)和蓝奶龙( B B B)相遇,他们都会变成黄奶龙( Y Y Y),那么就有

n : = n − 1 , m : = m − 1 , k : = k + 2. \begin{align*} n &:= n - 1, \\ m &:= m - 1, \\ k &:= k + 2. \end{align*} nmk:=n1,:=m1,:=k+2.

观察发现,任意两者之间的差值关于 3 3 3 的余数都没有变化。

从结果出发,即 ( s , 0 , 0 ) , ( 0 , s , 0 ) , ( 0 , 0 , s ) (s, 0, 0), (0, s, 0), (0, 0, s) (s,0,0),(0,s,0),(0,0,s) 其中之一,我们发现最终的 n ′ , m ′ , k ′ n', m', k' n,m,k 一定满足:

  • 其中两个数对 3 3 3 的余数是相同的。

时间复杂度 O ( T ) O(T) O(T)

C++ Code

#include <bits/stdc++.h>using i64 = long long;void solve() {i64 n, m, k;std::cin >> n >> m >> k;std::set<int> s {n % 3, m % 3, k % 3};if (s.size() < 3) {std::cout << "Yes\n";} else {std::cout << "No\n";}
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int T = 1;std::cin >> T;while (T--) {solve();}return 0;
}

D. 多米诺骨牌

题目大意

还是在牛客看题面吧()

Solution

由于我是 0-indexed,所以下面的叙述全都是在原题的基础上下标 − 1 -1 1

原题中 a i + 0.5 a_i + 0.5 ai+0.5 的位置,设其高度为 h h h(这是整数),能覆盖的区间是 [ a i + 0.5 − h , a i + 0.5 ] [a_i + 0.5 - h, a_i + 0.5] [ai+0.5h,ai+0.5],整点覆盖区间就是 ( a i + 0.5 − h , a i + 0.5 ) (a_i + 0.5 - h, a_i + 0.5) (ai+0.5h,ai+0.5),由于浮点有误差,所以我们可以将其变为整点,也就是 a i : = a i + 0.5 a_i := a_i + 0.5 ai:=ai+0.5,这样覆盖区间就变成 [ a i − h , a i ) [a_i - h, a_i) [aih,ai)(此时 a i a_i ai 是整点)。

根据题意,覆盖到的区间可以传递,因此我们只要保证 [ 0 , n ) [0, n) [0,n) 都能被覆盖到。因此对于 [ a i − h , a i ) [a_i - h, a_i) [aih,ai) 这样的覆盖区间,我们可以用差分统计,最后做一下前缀和得到 s s s 数组。

设现在未覆盖的点(即 s i = 0 s_i = 0 si=0 的位置)有 s u m \rm{sum} sum 个,对于当前的操作,我们把 a x a_x ax 改为 y y y,那么 a x a_x ax 的覆盖区间 [ a x − h , a x ) [a_x - h, a_x) [axh,ax) 会变为 [ a x − h + 1 , a x ) [a_x - h + 1, a_x) [axh+1,ax),因为高度少了 1 1 1,而对于 y y y [ y − h , y ) [y - h, y) [yh,y) 会扩展为 [ y − h − 1 , y ) [y - h - 1, y) [yh1,y)

这样就可以在 a x − h a_x - h axh 上和 y − h − 1 y - h - 1 yh1 上进行单点修改。

时间复杂度 O ( n + q ) O(n + q) O(n+q)

C++ Code

#include <bits/stdc++.h>int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int n, m;std::cin >> n >> m;std::vector<int> a(n);std::vector<int> h(n + 2);for (int i = 0; i < n; i++) {std::cin >> a[i];h[a[i]]++;}std::vector<int> s(n + 1);for (int i = 1; i <= n; i++) {s[std::max(i - h[i], 0)]++;s[i]--;}int sum = s[0] == 0;for (int i = 1; i < n; i++) {s[i] += s[i - 1];sum += s[i] == 0;}while (m--) {int x, y;std::cin >> x >> y;x--;int &p = a[x];if (p >= h[p] and --s[p - h[p]] == 0) {sum++;}h[p]--;h[y]++;if (y >= h[y] and s[y - h[y]]++ == 0) {sum--;}p = y;std::cout << sum << "\n";}return 0;
}

E. 找出猫猫虫

题目大意

给定 N N N 对数 ( L i , R i ) (L_i, R_i) (Li,Ri),要求你构造一个数组 X X X,满足:

  • ∣ X ∣ = N |X| = N X=N
  • ∀ i ∈ [ 1 , N ] \forall i \in [1, N] i[1,N],均有 X i ∈ [ L i , R i ] X_i \in [L_i, R_i] Xi[Li,Ri]
  • ∑ i = 1 N X i = 0 \sum\limits_{i = 1}^{N}X_i = 0 i=1NXi=0

数据范围

  • 1 ≤ N ≤ 2 ⋅ 1 0 5 , 1 \leq N \leq 2 \cdot 10^5, 1N2105,
  • − 1 0 9 ≤ L i , R i ≤ 1 0 9 . -10^9 \leq L_i, R_i \leq 10^9. 109Li,Ri109.

Solution

很明显我们需要贪心。

首先令 s L = ∑ i = 1 N L i , s R = ∑ i = 1 N R i sL = \sum\limits_{i = 1}^{N}L_i, \ sR = \sum\limits_{i = 1}^{N}R_i sL=i=1NLi, sR=i=1NRi,若 s L > 0 sL > 0 sL>0 s R < 0 sR < 0 sR<0,则一定无法满足 ∑ i = 1 N X i = 0 \sum\limits_{i = 1}^{N}X_i = 0 i=1NXi=0

否则我们从 s L sL sL 开始,尝试往里填充 − s L -sL sL。令 a d d = − s L add = -sL add=sL,每次需要填充的数为 min ⁡ ( a d d , R i − L i ) \min(add, R_i - L_i) min(add,RiLi),最后判断 a d d add add 是否减到 0 0 0 即可。

时间复杂度 O ( N ) O(N) O(N)

C++ Code

#include <bits/stdc++.h>using i64 = long long;template<class T, class U>
std::istream &operator>>(std::istream &is, std::pair<T, U> &p) {is >> p.first >> p.second;return is;
}
template<class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {for (auto &x: v) {is >> x;}return is;
}
template<class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {os << v[0];for (size_t i = 1; i < v.size(); i++) {os << " " << v[i];}return os;
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int N;std::cin >> N;std::vector<std::pair<int, int>> cat(N);std::cin >> cat;i64 sL = 0;i64 sR = 0;for (const auto &[L, R]: cat) {sL += L;sR += R;}if (sL > 0 or sR < 0) {std::cout << "No\n";return 0;}i64 add = -sL;std::vector<int> X;X.reserve(N);for (const auto &[L, R]: cat) {X.push_back(L);int x = std::min<i64>(R - L, add);X.back() += x;add -= x;}if (add == 0) {std::cout << "Yes\n";std::cout << X << "\n";} else {std::cout << "No\n";}return 0;
}

F. 点灯

题目大意

这个讲起来有点麻烦,可以直接去题目链接里看题意,大致就是放灯泡,灯泡之间不能互相照亮,求最多能放的灯泡数。

数据范围

  • 2 ≤ n , m ≤ 200 , 2 \leq n, m \leq 200, 2n,m200,
  • 0 ≤ a i , j < 2. 0 \leq a_{i, j} < 2. 0ai,j<2.

Solution

说实话我记得在某届篮球杯看到过类似的题,当时群友说的就是二分图最大匹配,所以我就试了一下,然后也算歪打正着对了。

看官解的描述是这样转化的:

  • 称横向每一段黑色格子的右边线为横墙,竖向每一段黑色格子左边线为竖墙。每一个灯泡都对应唯一一段横墙和竖墙。为了使得两个灯泡不互相照亮,每一个横墙或竖墙都得唯一对应一个灯泡。将每一段白色格子所对应横墙和竖墙连一条边,问题就转化成了二分图最大匹配问题。

时间复杂度 O ( n 3 ) O(n^3) O(n3)

  • 我这个板子好久了,但是复杂度应该蛮低的,可能不到 O ( n 3 ) O(n^3) O(n3)

C++ Code

#include <bits/stdc++.h>using i64 = long long;template<class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {for (auto &x: v) {is >> x;}return is;
}struct augment_path {std::vector<std::vector<int>> g;std::vector<int> pa;  // 匹配std::vector<int> pb;std::vector<int> vis;  // 访问int n, m;         // 两个点集中的顶点数量int dfn;          // 时间戳记int res;          // 匹配数augment_path(int _n, int _m): n{_n}, m{_m} {assert(0 <= n and 0 <= m);pa = std::vector<int>(n, -1);pb = std::vector<int>(m, -1);vis = std::vector<int>(n);g.resize(n);res = 0;dfn = 0;}void add(int from, int to) {assert(0 <= from and from < n and 0 <= to and to < m);g[from].push_back(to);}bool dfs(int v) {vis[v] = dfn;for (int u: g[v]) {if (pb[u] == -1) {pb[u] = v;pa[v] = u;return true;}}for (int u: g[v]) {if (vis[pb[u]] != dfn and dfs(pb[u])) {pa[v] = u;pb[u] = v;return true;}}return false;}int match() {while (true) {dfn += 1;int cnt = 0;for (int i = 0; i < n; i += 1) {if (pa[i] == -1 and dfs(i)) {cnt += 1;}}if (cnt == 0) {break;}res += cnt;}return res;}
};int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int n, m;std::cin >> n >> m;std::vector g(n, std::vector(m, 0));for (auto &v: g) {std::cin >> v;}int N = 0;std::vector row(n, std::vector(m, -1));for (int i = 0; i < n; i++) {int k = -1;for (int j = 0; j < m; j++) {if (g[i][j] == 1) {k = -1;continue;}if (k < 0) {k = N++;}row[i][j] = k;}}int M = 0;std::vector col(n, std::vector(m, -1));for (int j = 0; j < m; j++) {int k = -1;for (int i = 0; i < n; i++) {if (g[i][j] == 1) {k = -1;continue;}if (k < 0) {k = M++;}col[i][j] = k;}}augment_path ag(N, M);for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (g[i][j] == 0) {ag.add(row[i][j], col[i][j]);}}}std::cout << ag.match() << "\n";return 0;
}

G. 俄罗斯方块

题目大意

给定七个俄罗斯方块的数量,分别为 I , O , T , J , L , S , Z I, O, T, J, L, S, Z I,O,T,J,L,S,Z,保证 T = S = Z = 0 T = S = Z = 0 T=S=Z=0。下图为示例。
HBUT 2025 校赛 G 图示
现在要拼成一个 2 × 2 K 2 \times 2K 2×2K 的矩阵,要求矩阵的每个格子都要被其中一个方块占据,且方块不能超出 2 × 2 K 2 \times 2K 2×2K 这个矩阵的边缘。同时,方块不能翻转,只能旋转。

K K K 的最大值。

数据范围

  • 0 ≤ I , O , T , J , L , S , Z ≤ 1 0 9 , 0 \leq I, O, T, J, L, S, Z \leq 10^9, 0I,O,T,J,L,S,Z109,
  • T = S = Z = 0. T = S = Z = 0. T=S=Z=0.

Solution

显然 O O O 这个四四方方的直接往上放就好。

对于 I , J , L I, J, L I,J,L,第一想法都是两个 I I I 变成 2 × 4 2 \times 4 2×4,两个 J J J L L L) 变成 2 × 4 2 \times 4 2×4

但是有一种特殊情况,就是 I I I 作为底,左上角一个 L L L,右上角一个 J J J,这样能凑出 2 × 6 2 \times 6 2×6。而这个 2 × 6 2 \times 6 2×6 最多只出现一次,因为假设出现 2 2 2 次,就相当于 2 × 12 2 \times 12 2×12,根据上面所说,可以变成 3 3 3 2 × 4 2 \times 4 2×4,分别是 2 I 2I 2I 组合, 2 J 2J 2J 组合, 2 L 2L 2L 组合,这是等价的。

时间复杂度 O ( 1 ) O(1) O(1)

C++ Code

#include <bits/stdc++.h>using i64 = long long;int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);i64 I, O, T, J, L, S, Z;std::cin >> I >> O >> T >> J >> L >> S >> Z;i64 min = std::min({I, J, L});int i = I % 2;int j = J % 2;int l = L % 2;int s = i + j + l;i64 ans = O;if (min == 0) {ans += (I - i) + (J - j) + (L - l);} else {ans += (I + J + L) - std::min(s, 3 - s);}std::cout << ans << "\n";return 0;
}

H. Super big cup

题目大意

给定一个长度为 n n n 的数组 a a a,对其做 m m m 次操作,每次操作如下:

  • 给定区间 [ l , r ] ⊂ [ 1 , n ] [l, r] \subset [1, n] [l,r][1,n] x x x,然后在此区间内随机等概率地选择一个 p p p,令 a p = x a_p = x ap=x

m m m 次操作后每个 a i a_i ai 的期望。答案对 998244353 998244353 998244353 取模。

数据范围

  • 1 ≤ n , m ≤ 2 ⋅ 1 0 5 , 1 \leq n, m \leq 2 \cdot 10^5, 1n,m2105,
  • 1 ≤ a i ≤ 1 0 9 , 1 \leq a_i \leq 10^9, 1ai109,
  • 1 ≤ l ≤ r ≤ n , 1 \leq l \leq r \leq n, 1lrn,
  • 0 ≤ x ≤ 1 0 9 . 0 \leq x \leq 10^9. 0x109.

Solution

对于一个 [ l , r ] [l, r] [l,r],考虑 i ∈ [ l , r ] i \in [l, r] i[l,r] a i a_i ai p = 1 r − l + 1 p = \frac{1}{r - l + 1} p=rl+11 的概率被选中被改为 x x x,有 1 − p = r − l r − l + 1 1 - p = \frac{r - l}{r - l + 1} 1p=rl+1rl 的概率不变,因此有 a i ′ = ( 1 − p ) a i + p ⋅ x . a_i' = (1 - p)a_i + p\cdot x. ai=(1p)ai+px. 于是我们发现了熟悉的形式:对旧值乘一个系数,加一个偏移量,这就是线段树的经典题目了。

简单来说,维护乘积积 m u l \rm{mul} mul,以及偏移量 a d d \rm{add} add,每次修改只要

m u l : = ( 1 − p ) ⋅ m u l , a d d : = ( 1 − p ) ⋅ a d d + p ⋅ x . \begin{align*} mul &:= (1 - p)\cdot mul, \\ add &:= (1 - p) \cdot add + p \cdot x. \end{align*} muladd:=(1p)mul,:=(1p)add+px.

时间复杂度 O ( ( n + m ) log ⁡ n + m log ⁡ V ) O(\rm{(n + m)}\log n + m\log V) O((n+m)logn+mlogV)

  • 其中 log ⁡ n \log n logn 是线段树操作, log ⁡ V \log V logV 是求逆元操作。

C++ Code

#include <bits/stdc++.h>using i64 = long long;template<class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {for (auto &x: v) {is >> x;}return is;
}template<class T>
constexpr T power(T a, i64 b) {T res = 1;for (; b; b /= 2, a *= a) {if (b % 2) {res *= a;}}return res;
}
template<int P>
struct MInt {int x;constexpr MInt() : x{} {}constexpr MInt(i64 x) : x{norm(x % getMod())} {}static int Mod;constexpr static int getMod() {if (P > 0) {return P;} else {return Mod;}}constexpr static void setMod(int Mod_) {Mod = Mod_;}constexpr int norm(int x) const {if (x < 0) {x += getMod();}if (x >= getMod()) {x -= getMod();}return x;}constexpr int val() const {return x;}explicit constexpr operator int() const {return x;}constexpr MInt operator-() const {MInt res;res.x = norm(getMod() - x);return res;}constexpr MInt inv() const {assert(x != 0);return power(*this, getMod() - 2);}constexpr MInt &operator*=(MInt rhs) & {x = 1LL * x * rhs.x % getMod();return *this;}constexpr MInt &operator+=(MInt rhs) & {x = norm(x + rhs.x);return *this;}constexpr MInt &operator-=(MInt rhs) & {x = norm(x - rhs.x);return *this;}constexpr MInt &operator/=(MInt rhs) & {return *this *= rhs.inv();}friend constexpr MInt operator*(MInt lhs, MInt rhs) {MInt res = lhs;res *= rhs;return res;}friend constexpr MInt operator+(MInt lhs, MInt rhs) {MInt res = lhs;res += rhs;return res;}friend constexpr MInt operator-(MInt lhs, MInt rhs) {MInt res = lhs;res -= rhs;return res;}friend constexpr MInt operator/(MInt lhs, MInt rhs) {MInt res = lhs;res /= rhs;return res;}friend constexpr std::istream &operator>>(std::istream &is, MInt &a) {i64 v;is >> v;a = MInt(v);return is;}friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) {return os << a.val();}friend constexpr bool operator==(MInt lhs, MInt rhs) {return lhs.val() == rhs.val();}friend constexpr bool operator!=(MInt lhs, MInt rhs) {return lhs.val() != rhs.val();}
};template<>
int MInt<0>::Mod = 998244353;template<int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();constexpr int P = 998244353;
using Z = MInt<P>;template<class Info, class Tag>
struct LazySegmentTree {#define l(p) (p << 1)#define r(p) (p << 1 | 1)int n;std::vector<Info> info;std::vector<Tag> tag;LazySegmentTree() {}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());auto build = [&](auto self, int p, int l, int r) {if (r - l == 1) {info[p] = _init[l];return;}int m = l + r >> 1;self(self, l(p), l, m);self(self, r(p), m, r);pull(p);};build(build, 1, 0, n);}void pull(int p) {info[p] = info[l(p)] + info[r(p)];}void apply(int p, const Tag &v, int len) {info[p].apply(v, len);tag[p].apply(v);}void push(int p, int len) {apply(l(p), tag[p], len / 2);apply(r(p), tag[p], len - len / 2);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 >> 1;push(p, r - l);if (x < m) {modify(l(p), l, m, x, v);} else {modify(r(p), m, r, x, v);}pull(p);}void modify(int p, const Info &v) {modify(1, 0, n, p, v);}Info query(int p, int l, int r, int x, int y) {if (l >= y or r <= x) {return Info();}if (l >= x and r <= y) {return info[p];}int m = l + r >> 1;push(p, r - l);return query(l(p), l, m, x, y) + query(r(p), m, r, x, y);}Info query(int l, int r) {return query(1, 0, n, l, r);}void Apply(int p, int l, int r, int x, int y, const Tag &v) {if (l >= y or r <= x) {return;}if (l >= x and r <= y) {apply(p, v, r - l);return;}int m = l + r >> 1;push(p, r - l);Apply(l(p), l, m, x, y, v);Apply(r(p), m, r, x, y, v);pull(p);}void Apply(int l, int r, const Tag &v) {return Apply(1, 0, n, l, r, v);}template<class F>int findFirst(int p, int l, int r, int x, int y, F &&pred) {if (l >= y or r <= x) {return -1;}if (l >= x and r <= y and !pred(info[p])) {return -1;}if (r - l == 1) {return l;}push(p, r - l);int m = l + r >> 1;int res = findFirst(l(p), l, m, x, y, pred);if (res == -1) {res = findFirst(r(p), m, r, x, y, pred);}return res;}template<class F>int findFirst(int l, int r, F &&pred) {return findFirst(1, 0, n, l, r, pred);}template<class F>int findLast(int p, int l, int r, int x, int y, F &&pred) {if (l >= y or r <= x) {return -1;}if (l >= x and r <= y and !pred(info[p])) {return -1;}if (r - l == 1) {return l;}push(p, r - l);int m = l + r >> 1;int res = findLast(r(p), m, r, x, y, pred);if (res == -1) {res = findLast(l(p), l, m, x, y, pred);}return res;}template<class F>int findLast(int l, int r, F &&pred) {return findLast(1, 0, n, l, r, pred);}#undef l(p)#undef r(p)
};struct Tag {Z mul = 1;Z add = 0;void apply(const Tag &t) {mul = mul * t.mul;add = add * t.mul + t.add;}
};
struct Info {Z sum = 0;void apply(const Tag &t, int len) {sum = sum * t.mul + t.add;}
};
Info operator+(const Info &a, const Info &b) {return {a.sum + b.sum};
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int n, m;std::cin >> n >> m;std::vector<int> a(n);std::cin >> a;LazySegmentTree<Info, Tag> sgt(n);for (int i = 0; i < n; i++) {sgt.modify(i, {a[i]});}while (m--) {int l, r, x;std::cin >> l >> r >> x;l--;Z p = Z(r - l).inv();sgt.Apply(l, r, {1 - p, p * x});}for (int i = 0; i < n; i++) {std::cout << sgt.query(i, i + 1).sum << " \n"[i == n - 1];}return 0;
}

I. DeepSeek

Solution

前缀和 + 二分即可。

看官解是 d e e p s e e k \rm{deepseek} deepseek 出的,感觉还挺有意思。

时间复杂度 O ( Q log ⁡ N ) O(Q\log N) O(QlogN)

C++ Code

#include <bits/stdc++.h>using i64 = long long;template<class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {for (auto &x: v) {is >> x;}return is;
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int N, Q;std::cin >> N >> Q;std::vector<int> R(N);std::cin >> R;std::ranges::sort(R);std::vector<i64> s(N + 1);for (int i = 0; i < N; i++) {s[i + 1] = s[i] + R[i];}while (Q--) {i64 X;std::cin >> X;int i = std::ranges::upper_bound(s, X) - s.begin() - 1;std::cout << i << "\n";}return 0;
}

J. 湖工三宝

Solution

非常明显的反悔贪心。

具体做法已经套路化:对截止时间 e e e 排序,然后如果 T + t ≤ e T + t \leq e T+te,就选它;否则看大根堆里之前选的那些有没有 t ′ t' t 比当前的 t t t 大的,直接换掉。

官解似乎还有个 01 01 01 背包解法,感兴趣可以去看看。

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

C++ Code

#include <bits/stdc++.h>using i64 = long long;int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int n;std::cin >> n;std::vector<std::array<int, 4>> job(n);for (auto &[e, a, b, c]: job) {std::cin >> a >> b >> c >> e;}std::ranges::sort(job);int T = 0;int ans = 0;std::priority_queue<int> q;for (const auto &[e, a, b, c]: job) {int t = a + b + c;if (T + t <= e) {T += t;q.push(t);ans++;continue;}if (not q.empty() and q.top() > t) {T -= q.top(); q.pop();q.push(t);T += t;}}std::cout << ans << "\n";return 0;
}

K. 在哪签到?

Solution

直接输出 H B U T \rm{HBUT} HBUT

Python Code

print("HBUT")

L. 帮帮Carson

Solution

模拟题,直接三位三位模拟。

C++ Code

#include <bits/stdc++.h>int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::string s;std::cin >> s;int ans = std::numeric_limits<int>::max() / 2;for (int i = 0; i + 3 <= s.size(); i++) {ans = std::min(ans, std::abs(std::stoi(s.substr(i, 3)) - 753));}std::cout << ans << "\n";return 0;
}

M. 奶龙农场的宝藏计算

题目大意

给定 n n n 只奶绿,每只奶龙都有一个“可爱值”,用一个整数表示,可爱值越大越可爱。

农场主发现了一个神奇的现象:当几只奶龙聚在一起玩耍时,它们会创造出一个“快乐宝藏”,而宝藏的价值取决于这个小团体中“最可爱”的奶龙和“最不可爱”的奶龙的可爱值的乘积。

现在,农场主记录了所有奶龙的可爱值,形成了一个长度为 n n n 的序列 a a a

他想知道,如果考虑所有可能的奶龙组合(即所有非空子序列),这些组合创造的“快乐宝藏”的总价值是多少, 最后的结果模 998244353 998244353 998244353

数据范围

  • 1 ≤ n ≤ 2 ⋅ 1 0 5 , 1 \leq n \leq 2 \cdot 10^5, 1n2105,
  • 0 ≤ a i < 998244353. 0 \leq a_i < 998244353. 0ai<998244353.

Solution

长度为 1 1 1 的区间的快乐价值总和显然是 ∑ i = 1 n a i 2 . \sum\limits_{i = 1}^{n}a_i^2. i=1nai2. 下面考虑区间长度 > 1 > 1 >1 的。

a a a 已经排好序,当前选择的最小值为 a i a_i ai,最大值为 a j a_j aj,满足 j − i + 1 > 1 j - i + 1 > 1 ji+1>1

那么固定最大最小值的子序列就有 2 j − i − 1 2^{j - i - 1} 2ji1 种选法(中间爱选不选)。

因此总的价值是 ∑ i = 1 n − 1 ∑ j = i + 1 n 2 j − i − 1 a i ⋅ a j . \sum\limits_{i = 1}^{n - 1}\sum\limits_{j = i + 1}^{n}2^{j - i - 1}a_i \cdot a_j. i=1n1j=i+1n2ji1aiaj.

下面开始化简。

∑ i = 1 n − 1 ∑ j = i + 1 n 2 j − i − 1 a i ⋅ a j = ∑ i = 2 n ∑ j = 1 i − 1 2 i − j − 1 a i ⋅ a j = ∑ i = 2 n a i ( ∑ j = 1 i − 1 2 ( i − 1 ) − j a j ) . \begin{align*} \sum\limits_{i = 1}^{n - 1}\sum\limits_{j = i + 1}^{n}2^{j - i - 1}a_i \cdot a_j &= \sum\limits_{i = 2}^{n}\sum\limits_{j = 1}^{i - 1}2^{i - j - 1}a_i \cdot a_j \\ &= \sum\limits_{i = 2}^{n}a_i \left(\sum\limits_{j = 1}^{i - 1}2^{(i - 1) - j}a_j\right). \end{align*} i=1n1j=i+1n2ji1aiaj=i=2nj=1i12ij1aiaj=i=2nai(j=1i12(i1)jaj).

f ( i ) = ∑ j = 1 i − 1 2 ( i − 1 ) − j a j f(i) = \sum\limits_{j = 1}^{i - 1}2^{(i - 1) - j}a_j f(i)=j=1i12(i1)jaj,那么

f ( i + 1 ) = ∑ j = 1 i 2 i − j a j = ( ∑ j = 1 i − 1 2 i − j a j ) + a i = 2 ( ∑ j = 1 i − 1 2 ( i − 1 ) − j a j ) + a i = 2 f ( i ) + a i . \begin{align*} f(i + 1) &= \sum\limits_{j = 1}^{i}2^{i - j}a_j \\ &= \left(\sum\limits_{j = 1}^{i - 1}2^{i - j}a_j \right) + a_i \\ &= 2 \left(\sum\limits_{j = 1}^{i - 1}2^{(i - 1) - j}a_j \right)+ a_i \\ &= 2f(i) + a_i. \end{align*} f(i+1)=j=1i2ijaj=(j=1i12ijaj)+ai=2(j=1i12(i1)jaj)+ai=2f(i)+ai.

初值条件: f ( 1 ) = a 1 f(1) = a_1 f(1)=a1。于是求总和只要 O ( n ) O(n) O(n)

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

  • 瓶颈是排序。

C++ Code

#include <bits/stdc++.h>using i64 = long long;template<class T>
constexpr T power(T a, i64 b) {T res = 1;for (; b; b /= 2, a *= a) {if (b % 2) {res *= a;}}return res;
}
template<int P>
struct MInt {int x;constexpr MInt() : x{} {}constexpr MInt(i64 x) : x{norm(x % getMod())} {}static int Mod;constexpr static int getMod() {if (P > 0) {return P;} else {return Mod;}}constexpr static void setMod(int Mod_) {Mod = Mod_;}constexpr int norm(int x) const {if (x < 0) {x += getMod();}if (x >= getMod()) {x -= getMod();}return x;}constexpr int val() const {return x;}explicit constexpr operator int() const {return x;}constexpr MInt operator-() const {MInt res;res.x = norm(getMod() - x);return res;}constexpr MInt inv() const {assert(x != 0);return power(*this, getMod() - 2);}constexpr MInt &operator*=(MInt rhs) & {x = 1LL * x * rhs.x % getMod();return *this;}constexpr MInt &operator+=(MInt rhs) & {x = norm(x + rhs.x);return *this;}constexpr MInt &operator-=(MInt rhs) & {x = norm(x - rhs.x);return *this;}constexpr MInt &operator/=(MInt rhs) & {return *this *= rhs.inv();}friend constexpr MInt operator*(MInt lhs, MInt rhs) {MInt res = lhs;res *= rhs;return res;}friend constexpr MInt operator+(MInt lhs, MInt rhs) {MInt res = lhs;res += rhs;return res;}friend constexpr MInt operator-(MInt lhs, MInt rhs) {MInt res = lhs;res -= rhs;return res;}friend constexpr MInt operator/(MInt lhs, MInt rhs) {MInt res = lhs;res /= rhs;return res;}friend constexpr std::istream &operator>>(std::istream &is, MInt &a) {i64 v;is >> v;a = MInt(v);return is;}friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) {return os << a.val();}friend constexpr bool operator==(MInt lhs, MInt rhs) {return lhs.val() == rhs.val();}friend constexpr bool operator!=(MInt lhs, MInt rhs) {return lhs.val() != rhs.val();}
};template<>
int MInt<0>::Mod = 998244353;template<int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();constexpr int P = 998244353;
using Z = MInt<P>;template<class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {for (auto &x: v) {is >> x;}return is;
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int n;std::cin >> n;std::vector<int> a(n);std::cin >> a;std::ranges::sort(a);Z ans = std::accumulate(a.begin(), a.end(), Z(0), [&](Z s, int x) {return s + Z(x) * x;});Z dp = a[0];for (int i = 1; i < n; i++) {ans += a[i] * dp;dp = 2 * dp + a[i];}std::cout << ans << "\n";return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/43315.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CS2 DEMO导入blender(慢慢更新咯)

流程&#xff1a;cs2-sourcefilmmaker-blender 工具&#xff1a;cs2tools&#xff0c;cs2manager&#xff0c;blender&#xff0c;blender插件sourceio&#xff0c;source2viewer 导入sfm 工具界面 选择这个 sourceio插件 sourceIO其中新版本导入相机路径不见了&#xff0c…

一周学会Flask3 Python Web开发-SQLAlchemy数据迁移migrate

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 模型类(表)不是一成不变的&#xff0c;当你添加了新的模型类&#xff0c;或是在模型类中添加了新的字段&#xff0c;甚至是修改…

Postman CORS 测试完全指南:轻松模拟跨域请求,排查 CORS 相关问题

在使用 Postman 进行 API 测试时&#xff0c;通常不会遇到跨域问题&#xff0c;因为 Postman 是一个独立的客户端应用程序&#xff0c;不同于在浏览器中运行的 JavaScript 代码&#xff0c;它没有同源策略&#xff08;SOP&#xff09;的限制。跨域资源共享&#xff08;CORS&…

【图像处理基石】什么是refocus?

1. Refocus 的定义 Refocus&#xff08;重新对焦&#xff09;是一种通过算法调整图像或视频焦点的技术&#xff0c;允许用户在拍摄后选择焦点&#xff0c;实现类似光场相机的“先拍照后对焦”效果。其核心是通过多视角信息或深度估计&#xff0c;生成不同焦平面的图像&#xff…

kettle从入门到精通 第九十三课 ETL之kettle kettle 调用web service接口5种方法,一文彻底搞懂

场景&#xff1a;群里有小伙伴向我求助如何调用web service接口&#xff0c;趁着周末时间&#xff0c;给兄弟们搞demo。 1、本次使用的web service服务接口地址是http://ws.webxml.com.cn/WebServices/WeatherWS.asmx?opgetSupportCityDataset&#xff0c; 此接口根据用户输入…

电子电气架构 --- 域控架构下,汽车连接器的挑战和变化

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁,漫无目的走着,大概这就是成年人最深的孤独吧! 旧人不知我近况,新人不知我过…

[MySQL] 库的操作 表的操作

1.库的操作 1.创建数据库 这里就是一个创建数据库的例子&#xff0c;框内的东西可以不填&#xff0c;因为有默认设置&#xff0c;而这些东西是什么呢&#xff1f; 2.字符集和校验规则 2.1查看字符集校验规则 show variables like ‘character_set_database’; show variable…

Let’s Encrypt 宣布推出短期证书与 IP 地址支持,推动 Web 安全迈向新高度

2025 年 1 月 16 日&#xff0c;全球领先的免费 SSL/TLS 证书颁发机构 Let’s Encrypt 正式宣布两项重大功能更新计划&#xff1a;推出六天有效期证书&#xff08;Short-Lived Certificates&#xff09;及支持以 IP 地址为主体的证书申请。两项功能将于 2025 年起陆续开放&…

十二、Cluster集群

目录 一、集群简介1、现状问题2、集群作用 二、集群结构设计1、集群存储设2、消息通信设计 三、Cluster集群三主三从结构搭建1、redis.conf配置文件可配置项2、配置集群3、链接集群4、命令客户端连接集群并使用 四、集群扩容1、添加节点2、槽位分配3、添加从节点 五、集群缩容1…

Linux进程管理之子进程的创建(fork函数)、子进程与线程的区别、fork函数的简单使用例子、子进程的典型应用场景、父进程等待子进程结束后自己再结束

收尾 进程终止&#xff1a;子进程通过exit()或_exit()终止&#xff0c;父进程通过wait()或waitpid()等待子进程终止&#xff0c;并获取其退出状态。&#xff1f;其实可以考虑在另一篇博文中来写 fork函数讲解 fork函数概述 fork() 是 Linux 中用于创建新进程的系统调用。当…

【AI论文】挑战推理的边界:大型语言模型的数学基准测试

摘要&#xff1a;近年来&#xff0c;大型推理模型的迅猛发展导致现有用于评估数学推理能力的基准测试趋于饱和&#xff0c;这凸显出迫切需要更具挑战性和严谨性的评估框架。为填补这一空白&#xff0c;我们推出了OlymMATH&#xff0c;这是一项全新的奥林匹克级数学基准测试&…

典范硬币系统(Canonical Coin System)→ 贪心算法

【典范硬币系统】 ● 典范硬币系统&#xff08;Canonical Coin System&#xff09;是指使用贪心算法总能得到最少硬币数量解‌的货币面值组合‌。 ● 给定一个硬币系统 &#xff0c;若使其为典范硬币系统&#xff0c;则要求其各相邻面值比例 &#xff0c;及各开区间 内各金额…

Android7 Input(二)Linux 驱动层输入事件管理

概述 在Linux系统中&#xff0c;将键盘&#xff0c;鼠标&#xff0c;触摸屏等这类交互设备交由Linux Input子系统进行管理&#xff0c;Linux Input驱动子系统由于具有良好的和用户空间交互的接口。因此Linux Input驱动子系统&#xff0c;不止于只管理输入类型的设备。也可以将其…

高清壁纸一站式获取:海量分类,免费无弹窗

软件介绍 在如今这个追求个性化与高品质视觉体验的时代&#xff0c;一款出色的壁纸应用无疑能为我们的电子设备增添别样魅力。此刻&#xff0c;要给大家重磅推荐的便是Wallpaper这款应用&#xff0c;它犹如一个绚丽多彩的壁纸宝库&#xff0c;全方位满足你的审美需求。 海量壁…

Linux安装Cmake (Centos 7.9)

cmake安装 这个虽然已经更新到了4.0.0版本了&#xff0c;但是我们要用3.5版本的&#xff0c;因为这个比较稳定 官方地址&#xff1a;https://github.com/Kitware/CMake/releases/tag/v3.5.0&#xff0c;选择那个cmake-3.5.0-Linux-x86_64.tar.gz下载&#xff0c; 首先解压文…

Centos7,tar包方式部署rabbitmq-3.7.6

1. 环境准备 安装编译工具和依赖包 yum -y install make gcc gcc-c glibc-devel m4 perl openssl openssl-devel ncurses-devel ncurses-devel xz xmlto perl 2. Erlang环境搭建 版本对应&#xff1a;https://www.rabbitmq.com/docs/which-erlang 解压到指定目录 tar -xv…

【MySQL篇】事务管理,事务的特性及深入理解隔离级别

目录 一&#xff0c;什么是事务 二&#xff0c;事务的版本支持 三&#xff0c;事务的提交方式 四&#xff0c;事务常见操作方式 五&#xff0c;隔离级别 1&#xff0c;理解隔离性 2&#xff0c;查看与设置隔离级别 3&#xff0c;读未提交&#xff08;read uncommitted&a…

C++Primer学习(14.1 基本概念)

当运算符作用于类类型的运算对象时&#xff0c;可以通过运算符重载重新定义该运算符的含义。明智地使用运算符重载能令我们的程序更易于编写和阅读。举个例子&#xff0c;因为在Sales_item类中定义了输入、输出和加法运算符&#xff0c;所以可以通过下述形式输出两个Sales_item…

循相似之迹:解锁协同过滤的核心推荐逻辑

目录 一、引言二、协同过滤的基本原理三、协同过滤的算法类型&#xff08;一&#xff09;基于用户的协同过滤&#xff08;二&#xff09;基于物品的协同过滤 四、协同过滤的应用案例&#xff08;一&#xff09;电商平台的商品推荐&#xff08;二&#xff09;音乐平台的歌曲推荐…