CF题解——Trip to the Olympiad

本文最后更新于 9 个月前,文中所描述的信息可能已发生改变。

C. Trip to the Olympiad 解题思路 ​

核心目标与异或性质分析 ​

本题要求在给定范围 [L,R][L, R] 内,找到三个互不相同的数字 a,b,ca, b, c,使得目标和 Sum=(a⊕b)+(b⊕c)+(c⊕a)\text{Sum} = (a \oplus b) + (b \oplus c) + (c \oplus a) 最大。

我们首先分析异或和的性质。对于任意一个二进制位 ii,它对总和 Sum\text{Sum} 的贡献是 $ 2^i$ 乘以该位上三个异或结果 (a⊕b)i,(b⊕c)i,(c⊕a)i(a \oplus b)_i, (b \oplus c)_i, (c \oplus a)_i 之和。

在一个特定的位 ii 上,数字 a,b,ca, b, c 的位值(bit values)只有四种组合会产生非零贡献:

  1. (0,0,1)(0, 0, 1) 或其排列: 此时 (a⊕b)i=0,(b⊕c)i=1,(c⊕a)i=1(a \oplus b)_i = 0, (b \oplus c)_i = 1, (c \oplus a)_i = 1。总和为 $ 0 + 1 + 1 = 2$。
  2. (1,1,0)(1, 1, 0) 或其排列: 此时 (a⊕b)i=0,(b⊕c)i=1,(c⊕a)i=1(a \oplus b)_i = 0, (b \oplus c)_i = 1, (c \oplus a)_i = 1。总和为 $ 0 + 1 + 1 = 2$。
  3. (0,0,0)(0, 0, 0) 或 (1,1,1)(1, 1, 1): 此时所有异或结果均为 $ 0$。总和为 $ 0$。

因此,要使总和 Sum\text{Sum} 最大,我们应该尽量使高位的三个数字在该位上呈现 (0,0,1)(0, 0, 1) 或 (1,1,0)(1, 1, 0) 的模式,以保证每一位都能贡献最大值 $ 2 \cdot 2^i$。

寻找关键位 kk

quot;">​

由于 a,b,ca, b, c 必须在 [L,R][L, R] 范围内,我们不能随意构造数字。最大的挑战在于范围约束。

我们考虑范围的两个端点 LL 和 RR。它们之间的最高不同位是限制我们能构造出多少高位 $ 1$ 的关键。

  1. 计算 L⊕RL \oplus R: 得到一个数,其最高位 kk 标志着 LL 和 RR 在 $ 2^k$ 这一位上是不同的,而在所有更高的位( k+1,k+2,…k+1, k+2, \dots )上是相同的。
  2. 确定关键位 kk: kk 即为 L⊕RL \oplus R 的最高设置位(Most Significant Bit, MSB)的索引。
  • 如果 L=RL = R,则 L⊕R=0L \oplus R = 0,此时 k=0k=0(或 −1-1,我们取 k=0k=0 作为安全底线)。
  • 如果 L≠RL \neq R,则 如果 L≠RL \neq R,则 kk 为 L⊕RL \oplus R 的最高设置位(MSB)索引,且 k>0k > 0。

构造最优解 a,b,ca, b, c

quot;">​

在位 kk 以上,所有 [L,R][L, R] 范围内的数字都与 LL 和 RR 相同。我们最大化目标和的潜力在于位 $ 0$ 到 位 kk。为了最大化贡献,我们希望 a,b,ca, b, c 在这 k+1k+1 位上实现全 $ 1$ 模式的最高贡献。

我们构造两个数 aa 和 bb 如下:

  1. 构造 aa: 我们取 LL 的高位部分,并在位 $ 0$ 到 位 k−1k-1 上全部设置为 $ 1$。

    a=L∣((1≪k)−1)a = L \mid ((1 \ll k) - 1)

    这样构造的 aa 满足 L≤a≤RL \le a \le R 的条件,因为它只在 LL 的低位上做了“或 $ 1$”操作,且 LL 和 RR 在位 kk 上不同。

  2. 构造 bb: 我们希望 bb 能实现与 aa 在位 kk 上的翻转,并使低位部分尽可能贡献 $ 1$。

    b=a+1b = a + 1

    分析 aa 和 bb:

    • aa 在位 kk 以下全为 $ 1$。
    • b=a+1b = a+1 将使位 kk 以下全变为 $ 0$,并使位 kk 上的值从 aa 的值翻转(即 ak≠bka_k \neq b_k)。
    • 由于 aa 是由 LL 通过“或 $ 1$”操作得到的,它必然满足 L≤a≤RL \le a \le R。
    • b=a+1b = a+1 必然满足 L≤b≤RL \le b \le R。这是因为 RR 的高位部分与 LL 相同,但 RR 的位 kk 是 $ 1$,而 LL 的位 kk 是 $ 0。。a$ 和 bb 相当于取到了这个范围内的“最大跨度”数字。
  3. 构造 cc: 既然 aa 和 bb 已经实现了在关键位 kk 上的翻转,以及在所有低位上对 Sum\text{Sum} 的最大贡献(通过 aa 在 k−1k-1 位以下全是 $ 1$),剩下的第三个数字 cc 只需要满足:

    • L≤c≤RL \le c \le R
    • c≠ac \neq a 且 c≠bc \neq b(题目要求互不相同,但实际上对于最大化 Sum\text{Sum} 的影响不大,只要有三个数能达到最大 Sum\text{Sum} 即可)。

    最简单的取法是取 c=Lc = L 或 c=Rc = R,只要它不与 aa 或 bb 重复即可。由于范围 [L,R][L, R] 至少包含 $ 3$ 个数,我们可以保证找到一个不重复的 cc。

    例如,我们简单取 c=(a==L?R:L)c = (a == L ? R : L)。

CPP 代码实现 ​

cpp
#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

// 函数:获取最高设置位的索引
int get_msb_index(i64 n) {
    if (n == 0) {
        return -1;
    }

    // 从 63 位开始向下查找第一个 1
    for (int i = 63; i >= 0; --i) {
        if (n & (1LL << i)) {
            return i;
        }
    }
    return -1; // 理论上 n != 0 不会走到这里
}


void solve() {

    i64 l, r;
    cin >> l >> r;

    // 1. 找出 L 和 R 的最高不同位 k
    i64 xor_result = l ^ r;
    int k = get_msb_index(xor_result);

    // 边界情况:如果 L = R,则 k = -1。
    if (k < 0) {
        k = 0; // 此时 k 不影响后续 mask 的构造,但保证 a 至少是 l
    }

    // 2. 构造 mask,即 k 位以下的 1 ( 2^k - 1 )
    i64 mask = (1LL << k) - 1;

    // 3. 构造 a: L 的高位部分 + k 位以下全 1
    i64 a = l | mask;

    // 4. 构造 b: a + 1。
    i64 b = a + 1;

    // 5. 构造 c: 随便取 L 或 R 中与 a 不重复的一个。
    i64 c = (a == l ? r : l);

    // 实际验证:对于 L=99, R=109。
    // L = (01100011)_2, R = (01101101)_2
    // L ^ R = (00001110)_2. MSB k=3. mask =(00000111)_2 = 7.
    // a = L | 7 = 99 | 7 = 103. b = 104. c = 109.
    // (103 ^ 104) + (104 ^ 109) + (109 ^ 103) = 7 + 13 + 10 = 30.
    // 这是最大值。

    cout << a << " " << b << " " << c << "\n";
}

int main() {

    // 优化 I/O
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int test;
    cin >> test;

    while (test--) {
        solve();
    }
}
CF题解——Power of Points
“如何连接IPv6的服务器”