1 条题解

  • 0
    @ 2026-4-30 11:31:13

    B. Slice to Survive 详细题解

    题目描述

    决斗者 Mouf 和 Fouad 进入了一个 n×mn \times m 的网格竞技场。Fouad 的怪物起始位置在单元格 (a,b)(a, b),其中行的编号为 11nn,列的编号为 11mm

    Mouf 和 Fouad 将一直决斗,直到网格只剩下一个单元格为止。

    每回合流程

    每回合中:

    1. Mouf 先操作:他沿着某条行线或列线将网格切成两部分,然后丢弃不含 Fouad 怪物的那一部分。注意:网格必须至少有 22 个单元格,否则游戏已经结束。
    2. 然后,在同一回合中,Fouad 将他的怪物移动到剩余网格中的任意单元格(可以停留在原地)。

    Mouf 希望最小化回合数,而 Fouad 希望最大化回合数。如果双方都采取最优策略,这场决斗将持续多少回合?

    输入格式

    每个测试包含多个测试用例。
    第一行包含一个整数 tt1t1041 \le t \le 10^4)——测试用例的数量。
    接下来每个测试用例包含四个整数 n,m,a,bn, m, a, b2n,m1092 \le n, m \le 10^91an1 \le a \le n1bm1 \le b \le m)。

    输出格式

    对于每个测试用例,输出一个整数——双方都最优操作时,决斗将持续的回合数。

    题目分析

    核心观察

    1. 每回合 Mouf 只能切一刀:他可以选择水平切或垂直切,去掉不含怪物的一半。

    2. Fouad 可以移动怪物:在 Mouf 切完后,Fouad 会把怪物移动到剩余网格中对他最有利的位置,即让后续切割需要更多回合的位置

    3. 回合数与维度缩减的关系

      • 假设当前网格有 nn 行,怪物在第 aa 行。Mouf 水平切时,最多能保留的行数为:row_remain=min(a,na+1)\text{row\_remain} = \min(a, n - a + 1) 这是因为 Mouf 可以选择保留上面或下面,但只能保留包含怪物的一侧。
      • 类似地,假设当前网格有 mm 列,怪物在第 bb 列。Mouf 垂直切时,最多能保留的列数为:col_remain=min(b,mb+1)\text{col\_remain} = \min(b, m - b + 1)
    4. Fouad 的应对策略

      • 如果 Mouf 选择水平切,Fouad 会把怪物移动到垂直方向的最中间,让后续垂直切割时需要更多回合。
      • 如果 Mouf 选择垂直切,Fouad 会把怪物移动到水平方向的最中间
    5. 维度缩减的规律

      • 对于一个维度(行或列),每切一次,该维度的大小会减少。Fouad 会把怪物放到剩余部分的中间,因此每次只能将维度大小近似减半(向上取整)。
      • 把维度从 xx 减少到 11 所需的最少切割次数为 log2x\lceil \log_2 x \rceil

    最优策略分析

    Mouf 有两种选择:

    策略一:先水平切

    • 第 1 回合:Mouf 水平切,保留 row_remain=min(a,na+1)\text{row\_remain} = \min(a, n - a + 1) 行和全部 mm 列。
    • 第 1 回合结束后:Fouad 把怪物移动到剩余网格的中间列(使其远离边界)。
    • 后续回合
      • 水平方向:从 row_remain\text{row\_remain} 行缩减到 11 行,需要 log2(row_remain)\lceil \log_2(\text{row\_remain}) \rceil 回合。
      • 垂直方向:从 mm 列缩减到 11 列,需要 log2m\lceil \log_2 m \rceil 回合。
    • 总回合数:$$\text{ans}_1 = 1 + \lceil \log_2(\text{row\_remain}) \rceil + \lceil \log_2 m \rceil $$

    策略二:先垂直切

    • 第 1 回合:Mouf 垂直切,保留 col_remain=min(b,mb+1)\text{col\_remain} = \min(b, m - b + 1) 列和全部 nn 行。
    • 第 1 回合结束后:Fouad 把怪物移动到剩余网格的中间行。
    • 后续回合
      • 水平方向:从 nn 行缩减到 11 行,需要 log2n\lceil \log_2 n \rceil 回合。
      • 垂直方向:从 col_remain\text{col\_remain} 列缩减到 11 列,需要 log2(col_remain)\lceil \log_2(\text{col\_remain}) \rceil 回合。
    • 总回合数:$$\text{ans}_2 = 1 + \lceil \log_2 n \rceil + \lceil \log_2(\text{col\_remain}) \rceil $$

    最终答案

    Mouf 会选择两种策略中较小的回合数:

    ans=min(ans1,ans2)\text{ans} = \min(\text{ans}_1, \text{ans}_2)

    算法实现

    辅助函数:计算 log2x\lceil \log_2 x \rceil

    对于 x1x \ge 1

    • 如果 x=1x = 1,则 log21=0\lceil \log_2 1 \rceil = 0
    • 否则,可以使用内置函数 __lg 或位运算:$$\lceil \log_2 x \rceil = \text{bit\_width}(x) - 1 $$

    其中 bit_width(x)\text{bit\_width}(x) 表示 xx 的二进制位数。

    时间复杂度

    • 每个测试用例 O(1)O(1)
    • 总复杂度 O(t)O(t),满足 t104t \le 10^4 的要求

    标程

    #include <bits/stdc++.h>
    using namespace std;
    
    // 计算 ceil(log2(x))
    int ceil_log2(long long x) {
        if (x <= 1) return 0;
        // bit_width(x) = floor(log2(x)) + 1
        // ceil(log2(x)) = bit_width(x - 1)
        return 64 - __builtin_clzll(x - 1);
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        
        int t;
        cin >> t;
        while (t--) {
            long long n, m, a, b;
            cin >> n >> m >> a >> b;
            
            // 计算第一次切割后能保留的最大行数和列数
            long long row_remain = min(a, n - a + 1);
            long long col_remain = min(b, m - b + 1);
            
            // 策略一:先水平切
            long long ans1 = 1 + ceil_log2(row_remain) + ceil_log2(m);
            
            // 策略二:先垂直切
            long long ans2 = 1 + ceil_log2(n) + ceil_log2(col_remain);
            
            // 取较小值
            cout << min(ans1, ans2) << "\n";
        }
        
        return 0;
    }
    

    样例验证

    样例 1:n=2,m=2,a=1,b=1n=2, m=2, a=1, b=1

    • row_remain=min(1,21+1=2)=1\text{row\_remain} = \min(1, 2-1+1=2) = 1
    • col_remain=min(1,21+1=2)=1\text{col\_remain} = \min(1, 2-1+1=2) = 1
    • $\text{ans}_1 = 1 + \lceil \log_2 1 \rceil + \lceil \log_2 2 \rceil = 1 + 0 + 1 = 2$
    • $\text{ans}_2 = 1 + \lceil \log_2 2 \rceil + \lceil \log_2 1 \rceil = 1 + 1 + 0 = 2$
    • ans=min(2,2)=2\text{ans} = \min(2, 2) = 2

    样例 2:n=3,m=3,a=2,b=2n=3, m=3, a=2, b=2

    • row_remain=min(2,32+1=2)=2\text{row\_remain} = \min(2, 3-2+1=2) = 2
    • col_remain=min(2,32+1=2)=2\text{col\_remain} = \min(2, 3-2+1=2) = 2
    • $\text{ans}_1 = 1 + \lceil \log_2 2 \rceil + \lceil \log_2 3 \rceil = 1 + 1 + 2 = 4$
    • $\text{ans}_2 = 1 + \lceil \log_2 3 \rceil + \lceil \log_2 2 \rceil = 1 + 2 + 1 = 4$
    • ans=min(4,4)=4\text{ans} = \min(4, 4) = 4

    样例 4:n=2,m=7,a=2,b=2n=2, m=7, a=2, b=2

    • row_remain=min(2,22+1=1)=1\text{row\_remain} = \min(2, 2-2+1=1) = 1
    • col_remain=min(2,72+1=6)=2\text{col\_remain} = \min(2, 7-2+1=6) = 2
    • $\text{ans}_1 = 1 + \lceil \log_2 1 \rceil + \lceil \log_2 7 \rceil = 1 + 0 + 3 = 4$
    • $\text{ans}_2 = 1 + \lceil \log_2 2 \rceil + \lceil \log_2 2 \rceil = 1 + 1 + 1 = 3$
    • ans=min(4,3)=3\text{ans} = \min(4, 3) = 3

    所有样例均通过验证。

    数学公式总结

    设:

    • u=a1u = a - 1(到上边距离)
    • d=nad = n - a(到下边距离)
    • l=b1l = b - 1(到左边距离)
    • r=mbr = m - b(到右边距离)

    则:

    row_remain=min(u,d)+1\text{row\_remain} = \min(u, d) + 1 col_remain=min(l,r)+1\text{col\_remain} = \min(l, r) + 1

    最终答案为:

    $$\text{ans} = \min\left(1 + \lceil \log_2(\min(u, d) + 1) \rceil + \lceil \log_2 m \rceil,\ 1 + \lceil \log_2 n \rceil + \lceil \log_2(\min(l, r) + 1) \rceil\right) $$

    其中 log2x\lceil \log_2 x \rceil 可通过位运算快速计算。

    • 1

    信息

    ID
    6714
    时间
    1000ms
    内存
    256MiB
    难度
    (无)
    标签
    递交数
    0
    已通过
    0
    上传者