当前位置: 首页 > news >正文

【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, 1T105,
  • 1 ≤ n , m , k ≤ 1 0 9 . 1 \leq n, m, k \leq 10^9. 1n,m,k109.

Solution1

一个显然的想法是每次选一个最大的 L \rm\pmb{L} L,即选择边界的 L \rm\pmb{L} L,这就启发我们从边界的 n + ( m − 1 ) n + (m - 1) n+(m1) 个方块组成的 L \rm\pmb{L} L 选起,再转个 18 0 ∘ 180^{\circ} 180 选择另一半的 ( n − 1 ) + ( m − 2 ) (n - 1) + (m - 2) (n1)+(m2) 个方块 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+(m1)sum,说明选了第一个边界 L \rm\pmb{L} L 就可以走人了,花费 k k k 元;
  • 否则 n + ( m − 1 ) < s u m n + (m - 1) < \rm{sum} n+(m1)<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=1c((ni+1)+(mi))=i=1c((n+m)(2i1))=i=1c(n+m)i=1c(2i1)=(n+m)cc2=(n+mc)c.

而我们就是要求最小的 c c c,使得 ( n + m − c ) ⋅ c ≥ s u m (n + m - c) \cdot c \geq sum (n+mc)csum,这可以通过 二分 实现。最终答案就是 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)(m1),即选择了 n m − ( n − m ) − 1 nm - (n - m) - 1 nm(nm)1 个方块,我们只需说明 n m − ( n m − ( n − m ) − 1 ) = ( n − m ) + 1 nm - (nm - (n - m) - 1) = (n - m) + 1 nm(nm(nm)1)=(nm)+1 最多只占总和 n m nm nm 40 % 40\% 40% 即可。

只需证 ( n − m ) + 1 ≤ ⌊ 2 n m 5 ⌋ . (n - m) + 1 \leq \lfloor \frac{2nm}{5} \rfloor. (nm)+152nm.

考虑 ⌊ x ⌋ ≥ x − 1 \lfloor x \rfloor \geq x - 1 xx1,于是我们再换一个目标,想办法证明 ( 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. (nm)+152nm152nm.

化简一下得到 2 n m − 5 ( n − m ) ≥ 10 , 2nm - 5(n - m) \geq 10, 2nm5(nm)10, ( 2 m − 5 ) n + 5 m ≥ 10. (2m - 5)n + 5m \geq 10. (2m5)n+5m10.

由于 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, (2m5)n(235)3=3,5m53=15,

综上得到 ( 2 m − 5 ) n + 5 m ≥ 3 + 15 = 18 ≥ 10. (2m - 5)n + 5m \geq 3 + 15 = 18 \geq 10. (2m5)n+5m3+15=1810.

n ≤ m n \leq m nm 的情况同理可证。

时间复杂度 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+mc)csum 的最小的 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+sum0 后,考虑 Δ = ( 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)24 sum(2nm )24 sum=4(nmsum)>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)24 sum ,c2=2(n+m)+(n+m)24 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)24 sum ,因此 ⌈ c 1 ⌉ ≥ 1 \lceil c_1 \rceil \geq 1 c11,因此最小的 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=lri

给定 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, 1T104,
  • 1 ≤ L ≤ R ≤ 1 0 18 . 1 \leq L \leq R \leq 10^{18}. 1LR1018.

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=lri=2(r+l)(rl+1), 不论 l , r l, r l,r 的奇偶, r + l r + l r+l r − l r - l rl 的奇偶性一定是一样的,所以 ( r + l ) ( r − l + 1 ) (r + l)(r - l + 1) (r+l)(rl+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(kN)

那么除了 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=2x1+2x+1, l = x − 1 2 , r = x + 1 2 l = \frac{x - 1}{2}, r = \frac{x + 1}{2} l=2x1,r=2x+1 即可。
  • x x x 是( ≠ 2 k ,   ∀ k ∈ N \neq 2^k, \ \forall k \in N =2k, kN) 的偶数,那么一定有 x = a ⋅ b , x = a \cdot b, x=ab, 不妨设 a a a 为奇数(一定 ≥ 3 \geq 3 3), b b b 为偶数。
    • b > a − 1 2 b > \frac{a - 1}{2} b>2a1,那就构造 ∑ 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=b2a1b+2a1i=2a1(2b)+b=ab=x,
    • 否则就有 b ≤ a − 1 2 < a + 1 2 b \leq \frac{a - 1}{2} < \frac{a + 1}{2} b2a1<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+1b2a+1+b1i= i=2a+1b2a+1+bi (2a+1+b)=b(a+1)+2a+1(2a+1+b)=b(a+1)b=ba=x

综上,除了 2 k ( k ∈ N ) 2^k(k \in N) 2k(kN) 都能用连续自然数的和凑出来。

时间复杂度 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, 1T104,
  • 2 ≤ n ≤ 2 ⋅ 1 0 6 . 2 \leq n \leq 2 \cdot 10^6. 2n2106.

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=(n1)(Dn1+Dn2),

初值条件: 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 n1 种选择来将元素 n n n 放到其他位置。

假设 元素 n n n 被放置在位置 i ∈ [ 1 , n ) i \in [1, n) i[1,n),那么我们就需要考虑剩余 n − 1 n - 1 n1 个元素的错排。这个时候,我们有两种情况需要处理:

  • 元素 i i i 被放置到位置 n n n。这种情况下,剩下的 n − 2 n - 2 n2 个元素错排;
  • 元素 i i i 被放置到其他位置( ≠ n \neq n =n),此时我们需要将剩余的 n − 1 n - 1 n1 个元素错排。

最终答案就是 D n ( n − 1 ) n . \frac{D_n}{(n - 1)^n}. (n1)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. 1XN5105.

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} (N1)1(mod2),说明上面所说的状态是奇数次被访问到的,也就是 A l i c e \rm{Alice} Alice 必胜,因此 N ≡ 0 ( m o d 2 ) N \equiv 0 \pmod{2} N0(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;
}

相关文章:

  • 多模态工作idea讨论
  • HTTPS协议—加密算法和中间攻击人的博弈
  • 【Dive Into Stable Diffusion v3.5】2:Stable Diffusion v3.5原理介绍
  • Baklib驱动企业数字化内容管理升级
  • WebSocket接入SSL证书
  • Java面试黄金宝典11
  • 数据库锁机制
  • 《Oracle DBA入门实战:十大高频问题详解与避坑指南》
  • 智能飞鸟监测 守护高压线安全
  • 使用 Go 构建 MCP Server
  • 【yolo11自定义实例分割训练集教程】
  • 2.2.盈亏平衡分析
  • webstorm调试模式报错:Cannot detect a launch configuration
  • 快速入手:Nacos融合SpringCloud成为注册配置中心
  • MySQL 入门大全:常用函数
  • Flink启动任务
  • LVS的 NAT 模式实现 3 台RS的轮询访问
  • 【IntelliJ IDEA快速绑定Maven配置指南】
  • 2025年3月23日坚持写原创的第24天
  • 华为HCIE网络工程师培训选机构攻略
  • 浦江潮涌征帆劲,上海以高质量发展服务全国发展大局
  • 被围观的“英之园”,谁建了潮汕天价违建?
  • 公示资费套餐、规范营销行为,今年信息通信行业将办好这十件实事
  • 女排奥运冠军宋妮娜:青少年保持身心健康才能走得更远
  • 首次带人形机器人走科技节红毯,傅利叶顾捷:没太多包袱,很多事都能从零开始
  • 机器人为啥热衷“搞体育”,经济日报:是向加速融入日常生活发起的冲锋