1 条题解

  • 0
    @ 2025-10-24 8:14:42

    核心思路

    本题解法的核心是二进制分解思想

    1. 问题转化

    设一条边的初始任务为 ss,目标为 tt(代码中已转为 0m10 \sim m-1 表示)。
    我们想要一个排列 pp 使得 p(s)=tp(s) = t

    但一次排列作用在所有选中的边上,所以不能单独对每条边做。
    这里的关键是:我们可以用多次操作,每次只改变任务编号的某一位(在二进制意义下)。


    2. 二进制位独立处理

    因为 m32m \le 32,我们可以把任务编号看成 logm\log m 位二进制数。

    对于第 ii 位(i=0,1,2,3,4i = 0,1,2,3,4,因为 m32m \le 32,最多 5 位),我们做两次操作:

    • 第一次:将这一位为 0 的城市集合挂出排列,该排列的作用是将任务编号加上 2i2^i(模 mm
    • 第二次:将这一位为 1 的城市集合挂出同样的排列。

    这样,每条边根据其两端城市在这一位的异同,可能被作用 0 次、1 次或 2 次。


    3. 如何确定城市分组

    代码中的 dfs 是关键:

    dfs(v, u, (t - s + m) % m >> k & 1 ? c : !c, k);
    

    这里 (t - s + m) % m 是任务需要的变化量(模 mm)。
    >> k & 1 检查这个变化量的第 kk 位是否为 1。

    • 如果第 kk 位为 1,说明这条边在这一轮需要被作用奇数次(1 次)该排列。
    • 如果第 kk 位为 0,说明需要被作用偶数次(0 次或 2 次)。

    为了让每条边被作用次数符合要求,我们根据这个条件给节点染色:

    • 如果 (t - s) >> k & 1 == 1,则子节点颜色与父节点不同(这样该边两端颜色不同,在两次操作中只会被其中一次覆盖 → 总共作用 1 次)。
    • 否则,子节点颜色与父节点相同(这样该边两端颜色相同,在两次操作中要么都被覆盖(两端都在 0 集合或都在 1 集合)→ 总共作用 2 次,模 2 意义下等于 0 次变化)。

    4. 排列构造

    排列 pp 的作用是:

    p(j) = (j + (1 << i)) % m + 1
    

    即把任务编号加上 2i2^i(模 mm),再加 1 转回 1m1 \dots m 的表示。

    这样,作用一次就翻转了第 ii 位(在模 mm 的循环意义下)。


    5. 操作次数

    对每一位 ii,我们做 2 次操作(分别选颜色 0 的集合和颜色 1 的集合)。
    共 5 位,所以总共 5×2=105 \times 2 = 10 次操作,符合满分要求。


    重要公式

    1. 任务变化量: [ \Delta = (t - s + m) \bmod m ] 表示需要加多少才能从 sstt(模 mm)。

    2. 二进制位检查: [ \text{need_flip}_k = (\Delta \gg k) & 1 ] 判断第 kk 位是否需要翻转。

    3. 排列作用: [ p_k(j) = (j + 2^k) \bmod m + 1 ] 实现第 kk 位的翻转。

    • 1

    信息

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