1 条题解

  • 0
    @ 2026-4-11 18:11:11

    题意简述

    nn 个敌人,第 ii 个敌人生命值 hih_i,位置 xix_i(严格递增)。
    玩家选择一个整数位置 pp(可以与敌人重合),然后每次攻击:

    • 对距离 ppdd 的敌人造成 max(0,md)\max(0, m-d) 伤害,其中 mm 是攻击力。

    问:最少攻击次数,使得存在某个 pp,至少 kk 个敌人被击败(生命 0\le 0)。
    如果不存在这样的 pp,输出 1-1


    核心思路

    直接枚举攻击次数 qq 然后判断是否可行。
    因为 qq 越大越容易满足,所以可以二分答案


    二分可行性判断

    假设我们固定攻击次数为 qq(即二分中的 midmid)。

    11. 判断一个敌人能否在 qq 次攻击内被击败

    设需要 每次攻击至少造成的伤害 为:

    need=hiq\text{need} = \lceil \frac{h_i}{q} \rceil

    因为 qq 次总伤害需要 hi\ge h_i

    如果 need>m\text{need} > m,则不可能击败该敌人(因为最大单次伤害为 mm)。
    否则,该敌人可被击败。

    22. 可击败敌人对应的 pp 范围

    每次攻击对位置 xix_i 的敌人伤害为 mpxim - |p - x_i|,需要:

    mpxineedm - |p - x_i| \ge \text{need}

    即:

    pximneed|p - x_i| \le m - \text{need}

    因此 pp 必须在区间:

    $$[x_i - (m - \text{need}), \; x_i + (m - \text{need})] $$

    33. 转化为区间覆盖问题

    每个可击败的敌人对应一个整数区间 [Li,Ri][L_i, R_i],其中:

    $$L_i = x_i - (m - \text{need}), \quad R_i = x_i + (m - \text{need}) $$

    注意pp 可以是任意整数,所以区间端点需取整,但这里 xix_imneedm - \text{need} 都是整数,所以 Li,RiL_i, R_i 都是整数。

    问题变为:
    是否存在一个整数点 pp,被至少 kk 个这样的区间覆盖?


    44. 区间覆盖计数(扫描线)

    用差分思想:

    • 对每个区间 [L,R][L, R]
      • LL+1+1
      • R+1R+11-1(表示离开区间)

    然后按位置从小到大扫描,累加覆盖数,一旦 k\ge k 则可行。


    55. 二分边界

    • 下界 lo=0lo = 0(不可能,但作为起始)
    • 上界 hihi 可以设一个足够大的数,比如 101010^{10}

    但标程中说明:
    最大答案不会超过 max(hi)\max(h_i),因为攻击一次至少造成 11 点伤害。
    所以如果 hi=109hi = 10^9 仍不可行,输出 1-1


    66. 复杂度

    • 二分:O(log(maxh))O(\log(\max h))
    • 每次判断:O(nlogn)O(n \log n)(排序事件,用 mapmap 或离散化)
    • 总:O(nlognlog(maxh))O(n \log n \log (\max h)),可过。

    77. 对应代码逻辑(C++ 版)

    ll lo = 0, hi = 1e10;  // 上界设大一点
    while (hi - lo > 1) {
        ll mid = (lo + hi) / 2;
        map<ll, int> ev;
    
        for (int i = 0; i < n; i++) {
            ll need = (h[i] + mid - 1) / mid;  // ceil(hi / mid)
            if (need > m) continue;
    
            ll left = x[i] - m + need;
            ll right = x[i] + m - need + 1;  // 开区间右端点
            ev[left]++;
            ev[right]--;
        }
    
        ll sum = 0;
        bool ok = false;
        for (auto& [pos, delta] : ev) {
            sum += delta;
            if (sum >= k) {
                ok = true;
                break;
            }
        }
    
        if (ok) hi = mid;
        else lo = mid;
    }
    

    88. 最终答案

    如果 hi==1e10hi == 1e10 说明不可行,输出 1-1,否则输出 hihi


    99. 样例验证

    以第一个样例为例:

    • n=5,m=5,k=3n=5,m=5,k=3
      h=[7,7,7,7,7]h=[7,7,7,7,7]
      x=[1,2,3,4,5]x=[1,2,3,4,5]

    二分 mid=2mid=2

    • need=7/2=4need = \lceil 7/2 \rceil = 4
    • mneed=1m-need = 1
    • 敌人 ii 区间:[xi1,xi+1][x_i - 1, x_i + 1]
      • 敌人11: [0,2][0,2]
      • 敌人22: [1,3][1,3]
      • 敌人33: [2,4][2,4]
      • 敌人44: [3,5][3,5]
      • 敌人55: [4,6][4,6]

    扫描线:

    • 位置22 被敌人11,22,33 覆盖,共33k\ge k,可行。

    所以 mid=2mid=2 可行,继续二分更小值,发现 mid=1mid=1 不可行,答案 22


    1010. 注意点

    • 区间右端点处理成开区间,避免重复计数边界。
    • pp 是整数位置,所以 L,RL,R 直接取整。
    • need>m\text{need} > m,该敌人永远无法在 qq 次内击败,直接跳过。

    • 1

    信息

    ID
    6483
    时间
    1000ms
    内存
    256MiB
    难度
    3
    标签
    递交数
    1
    已通过
    1
    上传者