【2025 华中师范大学-菜鸟杯程序设计竞赛】部分题解
比赛链接
A. 期末复习
题目大意
给定 T T T 组数据,每组给定三个正整数 n , m , k n, m, k n,m,k。
对于一个 n × m n \times m n×m 的矩形,现在要求你做以下操作若干次,问能否使得 至少 60 % 60\% 60% 的方块被选中,如果不能输出 − 1 -1 −1;否则每次操作要花费 k k k 元,求 最小花费。
- 每次操作选择一些小方块组成的 L \rm\pmb{L} L 形方格,要求这个 L \rm\pmb{L} L 一定不能是一根棍,也不能是一个点。
数据范围
- 1 ≤ T ≤ 1 0 5 , 1 \leq T \leq 10^5, 1≤T≤105,
- 1 ≤ n , m , k ≤ 1 0 9 . 1 \leq n, m, k \leq 10^9. 1≤n,m,k≤109.
Solution1
一个显然的想法是每次选一个最大的 L \rm\pmb{L} L,即选择边界的 L \rm\pmb{L} L,这就启发我们从边界的 n + ( m − 1 ) n + (m - 1) n+(m−1) 个方块组成的 L \rm\pmb{L} L 选起,再转个 18 0 ∘ 180^{\circ} 180∘ 选择另一半的 ( n − 1 ) + ( m − 2 ) (n - 1) + (m - 2) (n−1)+(m−2) 个方块 L \rm\pmb{L} L,一直选到不能选,因此在正常情况下我们最多可以选择 min ( n , m ) − 1 \min(n, m) - 1 min(n,m)−1 轮 L \rm\pmb{L} L。
设 s u m = ⌈ n × m × 6 10 ⌉ \rm{sum = \lceil \frac{n \times m \times 6}{10} \rceil} sum=⌈10n×m×6⌉,表示至少要选择的方块数。
首先 min ( n , m ) = 1 \min(n, m) = 1 min(n,m)=1 那么一定无解,因为题目不允许选择一个竖直或者横着的棍子。
其次是 min ( n , m ) = 2 \min(n, m) = 2 min(n,m)=2 的情况。这种情况下需要特判。
- 如果 n + ( m − 1 ) ≥ s u m n + (m - 1) \geq \rm{sum} n+(m−1)≥sum,说明选了第一个边界 L \rm\pmb{L} L 就可以走人了,花费 k k k 元;
- 否则 n + ( m − 1 ) < s u m n + (m - 1) < \rm{sum} n+(m−1)<sum,说明不能直接把第一个边界 L \rm\pmb{L} L 全部选掉,应该留一块给对称的另一半,这样可以直接选完所有方块(想象一下 L \rm\pmb{L} L 和 7 \rm\pmb{7} 7 插在一起),花费 2 k 2k 2k 元。
min ( n , m ) > 2 \min(n, m) > 2 min(n,m)>2 的情况就一定可以满足了,后面给出证明,下面先谈计算。
设我们选了 c c c 轮,那就是 ∑ i = 1 c ( ( n − i + 1 ) + ( m − i ) ) = ∑ i = 1 c ( ( n + m ) − ( 2 i − 1 ) ) = ∑ i = 1 c ( n + m ) − ∑ i = 1 c ( 2 i − 1 ) = ( n + m ) ⋅ c − c 2 = ( n + m − c ) ⋅ c . \begin{align*} \sum\limits_{i = 1}^{c}((n - i + 1) + (m - i)) &= \sum\limits_{i = 1}^c((n + m) - (2i - 1)) \\ &= \sum\limits_{i = 1}^c(n + m) - \sum\limits_{i = 1}^{c}(2i - 1) \\ &= (n + m) \cdot c - c^2 \\ &= (n + m - c) \cdot c. \end{align*} i=1∑c((n−i+1)+(m−i))=i=1∑c((n+m)−(2i−1))=i=1∑c(n+m)−i=1∑c(2i−1)=(n+m)⋅c−c2=(n+m−c)⋅c.
而我们就是要求最小的 c c c,使得 ( n + m − c ) ⋅ c ≥ s u m (n + m - c) \cdot c \geq sum (n+m−c)⋅c≥sum,这可以通过 二分 实现。最终答案就是 c k ck ck。
下面是 min ( n , m ) > 2 \min(n, m) > 2 min(n,m)>2 一定可以满足题目要求的证明。
我们最多可以进行 min ( n , m ) − 1 \min(n, m) - 1 min(n,m)−1 轮,根据上面推导的公式,一共可以选择 ( n + m − ( min ( n , m ) − 1 ) ) ⋅ ( min ( n , m ) − 1 ) (n + m - (\min(n, m) - 1)) \cdot (\min(n, m) - 1) (n+m−(min(n,m)−1))⋅(min(n,m)−1) 个方块,根据 n + m = max ( n , m ) + min ( n , m ) n + m = \max(n, m) + \min(n, m) n+m=max(n,m)+min(n,m),化简一下就是 ( max ( n , m ) + 1 ) ⋅ ( min ( n , m ) − 1 ) (\max(n, m) + 1) \cdot (\min(n, m) - 1) (max(n,m)+1)⋅(min(n,m)−1) 根据对称性,不妨设 n > m n > m n>m,那么就是 ( n + 1 ) ( m − 1 ) (n + 1)(m - 1) (n+1)(m−1),即选择了 n m − ( n − m ) − 1 nm - (n - m) - 1 nm−(n−m)−1 个方块,我们只需说明 n m − ( n m − ( n − m ) − 1 ) = ( n − m ) + 1 nm - (nm - (n - m) - 1) = (n - m) + 1 nm−(nm−(n−m)−1)=(n−m)+1 最多只占总和 n m nm nm 的 40 % 40\% 40% 即可。
只需证 ( n − m ) + 1 ≤ ⌊ 2 n m 5 ⌋ . (n - m) + 1 \leq \lfloor \frac{2nm}{5} \rfloor. (n−m)+1≤⌊52nm⌋.
考虑 ⌊ x ⌋ ≥ x − 1 \lfloor x \rfloor \geq x - 1 ⌊x⌋≥x−1,于是我们再换一个目标,想办法证明 ( n − m ) + 1 ≤ 2 n m 5 − 1 ≤ ⌊ 2 n m 5 ⌋ . (n - m) + 1 \leq \frac{2nm}{5} - 1 \leq \lfloor \frac{2nm}{5} \rfloor. (n−m)+1≤52nm−1≤⌊52nm⌋.
化简一下得到 2 n m − 5 ( n − m ) ≥ 10 , 2nm - 5(n - m) \geq 10, 2nm−5(n−m)≥10, 即 ( 2 m − 5 ) n + 5 m ≥ 10. (2m - 5)n + 5m \geq 10. (2m−5)n+5m≥10.
由于 min ( n , m ) > 2 \min(n, m) > 2 min(n,m)>2,那就有 ( 2 m − 5 ) n ≥ ( 2 ⋅ 3 − 5 ) ⋅ 3 = 3 , 5 m ≥ 5 ⋅ 3 = 15 , (2m - 5)n \geq (2 \cdot 3 - 5) \cdot 3 = 3, \\ 5m \geq 5 \cdot 3 = 15, (2m−5)n≥(2⋅3−5)⋅3=3,5m≥5⋅3=15,
综上得到 ( 2 m − 5 ) n + 5 m ≥ 3 + 15 = 18 ≥ 10. (2m - 5)n + 5m \geq 3 + 15 = 18 \geq 10. (2m−5)n+5m≥3+15=18≥10.
n ≤ m n \leq m n≤m 的情况同理可证。
时间复杂度 O ( ∑ log n m ) O\rm{(\sum\log nm)} O(∑lognm)
C++ Code for Solution1
#include <bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using i80 = __int128_t;
using u80 = unsigned __int128_t;
using f64 = double;
using f80 = long double;
using i16 = short;
using u16 = unsigned short;
constexpr f64 pi = std::numbers::pi;
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve() {
int n, m, k;
std::cin >> n >> m >> k;
int maxc = std::min(n, m);
if (maxc == 1) {
std::cout << -1 << "\n";
return;
}
i64 sum = (3LL * n * m - 1) / 5 + 1;
if (maxc == 2) {
int ans = k * (1 + (sum > n + m - 1));
std::cout << ans << "\n";
return;
}
auto calc = [&](int c) {
return static_cast<i64>(n + m - c) * c;
};
int lo = 1, hi = maxc;
while (lo + 1 < hi) {
int m = lo + hi >> 1;
if (calc(m) >= sum) {
hi = m;
} else {
lo = m;
}
}
std::cout << static_cast<i64>(k) * hi << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout << std::fixed << std::setprecision(12);
int T = 1;
std::cin >> T;
while (T--) {
solve();
}
return 0;
}
Solution2
上面说到,求使得 ( n + m − c ) ⋅ c ≥ s u m (n + m - c) \cdot c \geq \rm{sum} (n+m−c)⋅c≥sum 的最小的 c c c 可以用二分,但是注意到这是个关于 c c c 的二次不等式,所以可以考虑用求根公式 O ( 1 ) O(1) O(1) 求解。
把不等式变为 c 2 − ( n + m ) c + s u m ≤ 0 c^2 - (n + m)c + \rm{sum} \leq 0 c2−(n+m)c+sum≤0 后,考虑 Δ = ( n + m ) 2 − 4 s u m ≥ ( 2 n m ) 2 − 4 s u m = 4 ( n m − s u m ) > 0 , \Delta = (n + m)^2 - 4 \ \rm{sum} \geq (2 \sqrt{nm})^2 - 4 \ \rm{sum} = 4(nm - \rm{sum}) > 0, Δ=(n+m)2−4 sum≥(2nm)2−4 sum=4(nm−sum)>0, 再用求根公式得到两个根
c 1 = ( n + m ) − ( n + m ) 2 − 4 s u m 2 , c 2 = ( n + m ) + ( n + m ) 2 − 4 s u m 2 . c_1 = \frac{(n + m) - \sqrt{(n + m)^2 - 4 \ \rm{sum}}}{2}, \\ c_2 = \frac{(n + m) + \sqrt{(n + m)^2 - 4 \ \rm{sum}}}{2}. c1=2(n+m)−(n+m)2−4 sum,c2=2(n+m)+(n+m)2−4 sum.
那么 c c c 的范围就是 [ max ( ⌈ c 1 ⌉ , 1 ) , min ( ⌊ c 2 ⌋ , min ( n , m ) − 1 ) ] [\max(\lceil c_1 \rceil, 1), \ \min(\lfloor c_2 \rfloor, \min(n, m) - 1)] [max(⌈c1⌉,1), min(⌊c2⌋,min(n,m)−1)]。
所以满足条件的最小的 c c c 是 max ( ⌈ c 1 ⌉ , 1 ) \max(\lceil c_1 \rceil, 1) max(⌈c1⌉,1),而 ( n + m ) > ( n + m ) 2 − 4 s u m (n + m) > \sqrt{(n + m)^2 - 4 \ \rm{sum}} (n+m)>(n+m)2−4 sum,因此 ⌈ c 1 ⌉ ≥ 1 \lceil c_1 \rceil \geq 1 ⌈c1⌉≥1,因此最小的 c c c 就是 ⌈ c 1 ⌉ \lceil c_1 \rceil ⌈c1⌉。
至于解的存在性在 S o l u t i o n 1 \rm\pmb{Solution1} Solution1 中已有证明。
时间复杂度 O ( T ) O(T) O(T)
C++ Code for Solution2
#include <bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using i80 = __int128_t;
using u80 = unsigned __int128_t;
using f64 = double;
using f80 = long double;
using i16 = short;
using u16 = unsigned short;
constexpr f64 pi = std::numbers::pi;
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve() {
int n, m, k;
std::cin >> n >> m >> k;
int maxc = std::min(n, m);
if (maxc == 1) {
std::cout << -1 << "\n";
return;
}
i64 sum = (3LL * n * m - 1) / 5 + 1;
if (maxc == 2) {
std::cout << k * (1 + (sum > n + m - 1)) << "\n";
return;
}
i64 c = std::ceil(((n + m) - std::sqrt(static_cast<i64>(n + m) * (n + m) - 4 * sum)) / 2);
std::cout << c * k << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout << std::fixed << std::setprecision(12);
int T = 1;
std::cin >> T;
while (T--) {
solve();
}
return 0;
}
C. 好数
题目大意
我们称正整数 x x x 为好数当且仅当存在正整数 l , r l, r l,r 满足 l < r l < r l<r,使得 x = ∑ i = l r i x = \sum\limits_{i = l}^{r}i x=i=l∑ri。
给定 T T T 组数据,每组给出一个区间 [ L , R ] [L, R] [L,R]。
对于每个 [ L , R ] [L, R] [L,R],问 [ L , R ] [L, R] [L,R] 中有多少个好数。
数据范围
- 1 ≤ T ≤ 1 0 4 , 1 \leq T \leq 10^4, 1≤T≤104,
- 1 ≤ L ≤ R ≤ 1 0 18 . 1 \leq L \leq R \leq 10^{18}. 1≤L≤R≤1018.
Solution
这个题其实是个经典结论了。我们考虑 x = ∑ i = l r i = ( r + l ) ( r − l + 1 ) 2 , x = \sum\limits_{i = l}^{r}i = \frac{(r + l)(r - l + 1)}{2}, x=i=l∑ri=2(r+l)(r−l+1), 不论 l , r l, r l,r 的奇偶, r + l r + l r+l 和 r − l r - l r−l 的奇偶性一定是一样的,所以 ( r + l ) ( r − l + 1 ) (r + l)(r - l + 1) (r+l)(r−l+1) 一定是一个偶(奇)数一个奇(偶)数,且那个奇数一定 ≥ 3 \geq 3 ≥3(题目规定 l < r l < r l<r),而最后还要除以 2 2 2,所以 x x x 一定不可能是 2 k ( k ∈ N ) 2^k(k \in N) 2k(k∈N)。
那么除了 2 k 2^k 2k,其他的正整数都能凑出来吗?打表可知确实可以,下面进行证明。
- 若 x x x 是( ≥ 3 \geq 3 ≥3 的)奇数,那么有 x = x − 1 2 + x + 1 2 , x = \frac{x - 1}{2} + \frac{x + 1}{2}, x=2x−1+2x+1, 取 l = x − 1 2 , r = x + 1 2 l = \frac{x - 1}{2}, r = \frac{x + 1}{2} l=2x−1,r=2x+1 即可。
- 若
x
x
x 是(
≠
2
k
,
∀
k
∈
N
\neq 2^k, \ \forall k \in N
=2k, ∀k∈N) 的偶数,那么一定有
x
=
a
⋅
b
,
x = a \cdot b,
x=a⋅b, 不妨设
a
a
a 为奇数(一定
≥
3
\geq 3
≥3),
b
b
b 为偶数。
- 若 b > a − 1 2 b > \frac{a - 1}{2} b>2a−1,那就构造 ∑ i = b − a − 1 2 b + a − 1 2 i = a − 1 2 ( 2 b ) + b = a ⋅ b = x , \sum\limits_{i = b - \frac{a - 1}{2}}^{b + \frac{a - 1}{2}}i = \frac{a - 1}{2} (2b)+ b = a \cdot b = x, i=b−2a−1∑b+2a−1i=2a−1(2b)+b=a⋅b=x,
- 否则就有 b ≤ a − 1 2 < a + 1 2 b \leq \frac{a - 1}{2} < \frac{a + 1}{2} b≤2a−1<2a+1,于是构造 ∑ i = a + 1 2 − b a + 1 2 + b − 1 i = ( ∑ i = a + 1 2 − b a + 1 2 + b i ) − ( a + 1 2 + b ) = b ⋅ ( a + 1 ) + a + 1 2 − ( a + 1 2 + b ) = b ⋅ ( a + 1 ) − b = b ⋅ a = x \begin{align*}\sum\limits_{i = \frac{a + 1}{2} - b}^{\frac{a + 1}{2} + b - 1}i &= \left(\sum\limits_{i = \frac{a + 1}{2} - b}^{\frac{a + 1}{2} + b}{i} \right) - \left(\frac{a + 1}{2} + b\right) \\ &= b \cdot (a + 1) + \frac{a + 1}{2} - \left(\frac{a + 1}{2} + b\right) \\ &= b \cdot (a + 1) - b \\ &= b \cdot a \\ &= x \end{align*} i=2a+1−b∑2a+1+b−1i= i=2a+1−b∑2a+1+bi −(2a+1+b)=b⋅(a+1)+2a+1−(2a+1+b)=b⋅(a+1)−b=b⋅a=x
综上,除了 2 k ( k ∈ N ) 2^k(k \in N) 2k(k∈N) 都能用连续自然数的和凑出来。
时间复杂度 O ( T ) O(T) O(T)
C++ Code
#include <bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using i80 = __int128_t;
using u80 = unsigned __int128_t;
using f64 = double;
using f80 = long double;
using i16 = short;
using u16 = unsigned short;
constexpr f64 pi = std::numbers::pi;
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int lg(i64 x) {
return x > 0 ? std::__lg(x) + 1: 0;
}
void solve() {
i64 L, R;
std::cin >> L >> R;
L--;
std::cout << (R - L) - (lg(R) - lg(L)) << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout << std::fixed << std::setprecision(12);
int T = 1;
std::cin >> T;
while (T--) {
solve();
}
return 0;
}
E. 交换offer
题目大意
给定 T T T 组数据,每组给定一个正整数 n n n,表示人数。
这 n n n 个人每人有一份 o f f e r \rm{offer} offer,每个人都可以将自己的 o f f e r \rm{offer} offer 随机交给其他人,问所有人都拿不到自己原来 o f f e r \rm{offer} offer 的概率是多少,答案对 998244353 998244353 998244353 取模。
数据范围
- 1 ≤ T ≤ 1 0 4 , 1 \leq T \leq 10^4, 1≤T≤104,
- 2 ≤ n ≤ 2 ⋅ 1 0 6 . 2 \leq n \leq 2 \cdot 10^6. 2≤n≤2⋅106.
Solution
其实就是一个全错排问题,设 D n D_n Dn 表示 n n n 个人的全错排数量,那么递推式就是
D n = ( n − 1 ) ( D n − 1 + D n − 2 ) , D_n = (n - 1)(D_{n - 1} + D_{n - 2}), Dn=(n−1)(Dn−1+Dn−2),
初值条件: D 1 = 0 , D 2 = 1 D_1 = 0, D_2 = 1 D1=0,D2=1。
其含义可以用 d p \rm{dp} dp 的转移方程来理解。
假设我们要将元素 n n n 排列到某个位置,但由于是错排,它不能出现在位置 n n n 上,所以我们有 n − 1 n - 1 n−1 种选择来将元素 n n n 放到其他位置。
假设 元素 n n n 被放置在位置 i ∈ [ 1 , n ) i \in [1, n) i∈[1,n),那么我们就需要考虑剩余 n − 1 n - 1 n−1 个元素的错排。这个时候,我们有两种情况需要处理:
- 元素 i i i 被放置到位置 n n n。这种情况下,剩下的 n − 2 n - 2 n−2 个元素错排;
- 元素 i i i 被放置到其他位置( ≠ n \neq n =n),此时我们需要将剩余的 n − 1 n - 1 n−1 个元素错排。
最终答案就是 D n ( n − 1 ) n . \frac{D_n}{(n - 1)^n}. (n−1)nDn.
时间复杂度 O ( max ( n ) + ∑ log n ) O(\max(\rm{n}) + \sum\log n) O(max(n)+∑logn)
C++ Code
#include <bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using i80 = __int128_t;
using u80 = unsigned __int128_t;
using f64 = double;
using f80 = long double;
using i16 = short;
using u16 = unsigned short;
constexpr f64 pi = std::numbers::pi;
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
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>;
std::vector<Z> D;
void init(int n) {
D.assign(n + 1, 0);
D[2] = 1;
for (int i = 3; i <= n; i++) {
D[i] = (i - 1) * (D[i - 1] + D[i - 2]);
}
}
void solve() {
int n;
std::cin >> n;
std::cout << (D[n] / power(Z(n - 1), n)) << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout << std::fixed << std::setprecision(12);
init(2000000);
int T = 1;
std::cin >> T;
while (T--) {
solve();
}
return 0;
}
F. 植树节
题目大意
原题是 c o d e f o r c e s \rm{codeforces} codeforces 的一道题:CF1363C Game On Leaves。
给定一棵 N N N 个结点的树, A l i c e \rm{Alice} Alice 和 B o b \rm{Bob} Bob 两人在树上博弈。一开始你指定了一个结点 X ∈ [ 1 , N ] X \in [1, N] X∈[1,N]。现在他们要轮流删除结点, A l i c e \rm{Alice} Alice 先手。
- 每次删除的结点只能是度为 1 1 1 的结点(也就是叶节点),且同时要删掉这条悬挂边。
谁先删掉 X X X 谁就获胜,问谁能获胜。
数据范围
- 1 ≤ X ≤ N ≤ 5 ⋅ 1 0 5 . 1 \leq X \leq N \leq 5 \cdot 10^5. 1≤X≤N≤5⋅105.
Solution
如果 X X X 是叶结点,那么先手必胜。
如果 X X X 不是叶节点,我们可以把 X X X 拎起来,让 X X X 作为根节点,然后按照层序遍历的逆序往上删除,那么删到最后一定剩下两个结点,一个是 X X X,一个是下面挂着的它的其中一个儿子 Y Y Y,此时 X X X 也是叶结点了,所以先到这个状态的必胜。
如果 ( N − 1 ) ≡ 1 ( m o d 2 ) (N - 1) \equiv 1 \pmod{2} (N−1)≡1(mod2),说明上面所说的状态是奇数次被访问到的,也就是 A l i c e \rm{Alice} Alice 必胜,因此 N ≡ 0 ( m o d 2 ) N \equiv 0 \pmod{2} N≡0(mod2) 则先手必胜。
时间复杂度 O ( N ) O(N) O(N)
C++ Code
#include <bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using i80 = __int128_t;
using u80 = unsigned __int128_t;
using f64 = double;
using f80 = long double;
using i16 = short;
using u16 = unsigned short;
constexpr f64 pi = std::numbers::pi;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int N;
std::cin >> N;
std::vector<int> deg(N);
for (int i = 1; i < N; i++) {
int u, v;
std::cin >> u >> v;
u--, v--;
deg[u]++;
deg[v]++;
}
int X;
std::cin >> X;
X--;
if (deg[X] == 1 or N % 2 == 0) {
std::cout << "xiaonian wins!\n";
} else {
std::cout << "coldtree wins!\n";
}
return 0;
}
I. 找出躺赢狗
Solution
模拟题,直接存分数和名字排序即可,这里浮点误差远到不了 0.1 0.1 0.1 的程度,但是我为了写 i n t \rm{int} int 的(比较好看),所以用字符串处理了一下。
C++ Code
#include <bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using i80 = __int128_t;
using u80 = unsigned __int128_t;
using f64 = double;
using f80 = long double;
using i16 = short;
using u16 = unsigned short;
constexpr f64 pi = std::numbers::pi;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<std::pair<int, std::string>> ans;
for (int i = 0; i < n; i++) {
std::string s;
std::string t;
std::cin >> s >> t;
int score = 0;
int p = t.find('.');
if (p == -1) {
score = std::stoi(t) * 10;
} else {
score = std::stoi(t.substr(0, p)) * 10 + std::stoi(t.substr(p + 1));
}
if (score <= 30) {
ans.emplace_back(score, s);
}
}
std::ranges::sort(ans);
std::cout << ans.size() << "\n";
for (const auto &[score, name]: ans) {
std::cout << name << "\n";
}
return 0;
}
J.
Solution
也是模拟题,直接开一个字符串 C D E F G A B \rm{CDEFGAB} CDEFGAB,然后找给定音名在这个字符串中的位置即可。
C++ Code
#include <bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using i80 = __int128_t;
using u80 = unsigned __int128_t;
using f64 = double;
using f80 = long double;
using i16 = short;
using u16 = unsigned short;
constexpr f64 pi = std::numbers::pi;
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
using namespace std::literals::string_literals;
auto s = "CDEFGAB"s;
void solve() {
char a, b;
std::cin >> a >> b;
if (s.find(a) < s.find(b)) {
std::cout << b << "\n";
} else {
std::cout << a << "\n";
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout << std::fixed << std::setprecision(12);
int T = 1;
std::cin >> T;
while (T--) {
solve();
}
return 0;
}