1 条题解

  • 0
    @ 2025-12-10 20:15:51

    「美团 CodeM 复赛」通信 题解

    题目回顾

    • NN 个信号塔,第 ii 个塔的位置是 ii,信号强度 XiX_i(互不相同)。
    • NN 个人,第 ii 个人的位置是 ii,向左走一格要 AA 秒,向右走一格要 BB 秒。
    • 传递规则:当 ii 有信息时,选择 jj1ji1 \le j \le i),令 k=argmaxjtiXtk = \arg\max_{j \le t \le i} X_t,然后 iijj 同时向 kk 移动,都到达 kk 后信息从 ii 传给 jj,两人瞬间回到原位置,ii 失去信息,jj 获得信息。
    • 对每个 ii 求信息传到 11 的最短时间 fif_i 及方案数 gig_i(模 2322^{32})。
    • f1=0, g1=1f_1=0,\ g_1=1
    • 输出 fi\oplus f_igi\oplus g_i(分别用 64 位有符号、32 位无符号类型计算异或)。

    一、数学模型化简

    1. 确定 kk

    由于 XX 互不相同,设 L(i)L(i)ii 左边第一个满足 XL(i)>XiX_{L(i)} > X_i 的位置(若不存在则 L(i)=1L(i) = -1,但方便起见可以设 L(1)=0L(1)=0 并特判)。
    对任意 j[1,i]j \in [1,i]

    • 如果 jL(i)j \le L(i),则区间 [j,i][j,i] 的最大值位置 k=L(i)k = L(i)(因为 XL(i)>XiX_{L(i)} > X_iL(i)L(i) 左边没有更大的跨过它)。
    • 如果 j>L(i)j > L(i),则 k=ik = iXiX_i[j,i][j,i] 的最大值)。

    2. 传递时间

    m=km = k

    情况 Am=im = ij>L(i)j > L(i)

    • iimm:距离 00,时间 00
    • jjmmjjii 左边,向右走 iji-j 格,每格 BB 秒,时间 B(ij)B(i-j)
    • 总时间 T(i,j)=max(0,B(ij))=B(ij)T(i,j) = \max(0, B(i-j)) = B(i-j)

    情况 Bm=L(i)m = L(i)jL(i)j \le L(i)

    • iimm:向左走 iL(i)i - L(i) 格,每格 AA 秒,时间 A(iL(i))A(i - L(i))
    • jjmm:向右走 L(i)jL(i) - j 格,每格 BB 秒,时间 B(L(i)j)B(L(i)-j)
    • 总时间 T(i,j)=max(A(iL(i)), B(L(i)j))T(i,j) = \max\big(A(i - L(i)),\ B(L(i)-j)\big)

    二、动态规划方程

    fif_i 为从 ii 传到 11 的最短时间,显然 f1=0f_1=0

    一次传递:从 ii 传到 jj 花费 T(i,j)T(i,j),然后从 jj 传到 11 花费 fjf_j
    所以:

    $$f_i = \min_{1 \le j < i} \big[ f_j + T(i,j) \big]. $$

    代入 T(i,j)T(i,j) 的分情况:

    1. j>L(i)j > L(i)fj+B(ij)=fjBj+Bif_j + B(i-j) = f_j - Bj + Bi。 令 hj=fjBjh_j = f_j - B \cdot j,则这部分最小值 = Bi+minj>L(i)hjB \cdot i + \min_{j > L(i)} h_j

    2. jL(i)j \le L(i)fj+max(A(iL(i)), B(L(i)j))f_j + \max\big(A(i-L(i)),\ B(L(i)-j)\big)
      C=A(iL(i))C = A(i-L(i)),则

      • B(L(i)j)C    jL(i)CBB(L(i)-j) \le C \iff j \ge L(i) - \frac{C}{B},则时间 = fj+Cf_j + C
      • j<L(i)CBj < L(i) - \frac{C}{B},则时间 = fj+B(L(i)j)=fj+BL(i)Bjf_j + B(L(i)-j) = f_j + B L(i) - B j

    所以这部分要分两段求最小值。


    三、数据结构设计

    观察:

    • j>L(i)j > L(i) 的部分,需要支持区间 min{hj}\min\{h_j\}
    • jL(i)j \le L(i) 的部分,需要支持:
      • 区间 [L(i)C/B,L(i)][L(i)- \lfloor C/B \rfloor, L(i)]min{fj}\min\{f_j\}(当 CC 较大时)。
      • 区间 [1,L(i)C/B1][1, L(i)- \lfloor C/B \rfloor - 1]min{fjBj}\min\{f_j - B j\}(再加 BL(i)B L(i))。

    C/BC/B 可能不是整数,且分界点会随 ii 变化。


    代码中的简化技巧

    在给定代码中,使用了线段树维护两个值:

    • min_value[0]:存 fjBjf_j - B j(用于 j>L(i)j > L(i) 的情况,但实际处理时是另一形式)。
    • min_value[1]:存 fj+BL(i)Bjf_j + B L(i) - B j
      不,从代码 awp.min_value[1] = dp[i] - 1LL * i * a 看,这里 aa 就是 AA,所以它存的是 fjAjf_j - A j?可能用于另一种对称情况。

    实际上,因为 T(i,j)T(i,j) 的表达式是对称的,可以用单调栈维护 L(i)L(i),并在栈变化时更新线段树的“偏移量”(delta),使得查询能在 O(logN)O(\log N) 完成。


    四、代码核心流程

    1. 读入 N,A,B,X[1N]N, A, B, X[1 \dots N]
    2. 单调栈L(i)L(i)(左侧第一个 XX 更大的位置)。
    3. 线段树 tree 维护两个值:
      • tree[id].min_value[0]:对应 fjBjf_j - B j(或者带偏移后的值)。
      • tree[id].min_value[1]:对应 fjAjf_j - A j(或者带偏移后的值)。 以及对应的方案数 cont[0]cont[1]
    4. 遍历 i=1Ni = 1 \dots N
      • 更新栈,并在栈弹出时更新线段树区间(update 操作,增减偏移量)。
      • 查询(query 函数)得到两个候选最小值和方案数,合并得到 fi,gif_i, g_i
      • ii 的信息插入线段树。
    5. 输出 f1fNf_1 \oplus \dots \oplus f_Ng1gNg_1 \oplus \dots \oplus g_N

    五、时间复杂度

    • 单调栈操作总 O(N)O(N)
    • 线段树每次更新或查询 O(logN)O(\log N)
    • 总复杂度 O(NlogN)O(N \log N),可过 N106N \le 10^6(常数较小)。

    六、关键点总结

    1. 分类讨论 jjL(i)L(i) 的位置关系,将 T(i,j)T(i,j) 化简为较简单的形式。
    2. max\max 表达式拆为分段函数,分别对应不同的 jj 范围。
    3. 用单调栈维护 L(i)L(i),并借助线段树动态维护两类最小值查询,支持区间加偏移量。
    4. 方案数在求最小值时同时累加(模 2322^{32})。
    5. 最终答案用异或输出。

    示例对应(样例):

    $$\begin{cases} f_1 = 0 & g_1 = 1 \\ f_2 = 3 & g_2 = 1 \\ f_3 = 13 & g_3 = 1 \\ f_4 = 9 & g_4 = 2 \\ f_5 = 12 & g_5 = 4 \\ f_6 = 13 & g_6 = 1 \end{cases} $$

    输出:

    6
    6
    
    • 1

    信息

    ID
    6047
    时间
    3000ms
    内存
    2048MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者