1 条题解

  • 0
    @ 2026-5-18 21:11:27

    D1. 无限序列(简单版本)详细题解

    一、题目理解

    定义一个无限二进制序列 aa

    • nn 项给定:a1,a2,,an{0,1}a_1, a_2, \dots, a_n \in \{0,1\}
    • 对于 m>nm > n:$$a_m = a_1 \oplus a_2 \oplus \dots \oplus a_{\lfloor m/2 \rfloor} $$其中 \oplus按位异或(对二进制来说,等同于模 22 加法)。

    给定 l=rl = r(简单版本),需要输出 ala_l


    二、核心观察

    1. 定义前缀异或

    S(m)=a1a2amS(m) = a_1 \oplus a_2 \oplus \dots \oplus a_m

    则:

    • 对于 m>nm > nam=S(m/2)a_m = S(\lfloor m/2 \rfloor)
    • S(m)=S(m1)amS(m) = S(m-1) \oplus a_m

    2. 递推式

    ama_m 代入:

    $$S(m) = S(m-1) \oplus S(\lfloor m/2 \rfloor) \quad (m > n) $$

    3. 边界条件

    • S(0)=0S(0) = 0
    • S(1),S(2),,S(n)S(1), S(2), \dots, S(n) 可直接计算

    三、标程算法解析

    标程使用了一个巧妙的数学化简,避免了复杂的递归。

    步骤 1:预处理前 2n2n

    vector<int> a(n + 1);
    vector<int> pref(n + 1);
    for (int i = 1; i <= n; i++) {
        pref[i] = pref[i - 1] + a[i];
    }
    

    pref[i]普通前缀和(不是异或),但这里实际上只需要奇偶性(模 22)。

    步骤 2:将 nn 调整为奇数

    if (n % 2 == 0) {
        n++;
        int cur = pref[n / 2] & 1;
        a.push_back(cur);
        pref.push_back(pref.back() + cur);
    }
    

    为什么? 因为递推中 nn 是奇数时规律更简洁。

    步骤 3:再扩展 2n2n

    for (int i = n + 1; i <= n * 2; i++) {
        a.push_back(pref[i / 2] & 1);
        pref.push_back(pref[i - 1] + a[i]);
    }
    

    这样我们有了 a1a2na_1 \dots a_{2n}

    步骤 4:计算 pp

    int p = pref[n] & 1;
    

    ppS(n)=a1++anS(n) = a_1 + \dots + a_n 的奇偶性(即异或和)。

    步骤 5:核心函数 get(x)

    auto get = [&](int64_t x) {
        int ret = 0;
        while (true) {
            if (x <= n * 2) {
                ret ^= a[x];
                break;
            }
            ret ^= p;
            if ((x / 2 - n) % 2 == 0) {
                break;
            }
            x /= 2;
        }
        return ret;
    };
    

    这个函数计算 axa_x 的逻辑:

    • 如果 x2nx \le 2n,直接查表
    • 否则,先异或上 pp(因为 ax=S(x/2)a_x = S(\lfloor x/2 \rfloor) 的奇偶性等于 pp 的若干倍)
    • 然后检查条件,决定是否继续递归

    四、数学原理

    关键结论(通过打表/推导)

    对于 m>nm > n,有:

    S(m)=S(m1)S(m/2)S(m) = S(m-1) \oplus S(\lfloor m/2 \rfloor)

    经过分析,S(m)S(m) 的奇偶性满足周期性和线性递推。标程通过扩展 2n2n 项并利用 p=S(n)mod2p = S(n) \bmod 2,将任意 xxaxa_x 计算归结为:

    1. 不断除以 22,直到 x2nx \le 2n
    2. 每层贡献一个 pp(当条件满足时)
    3. 最终查表得到结果

    五、为什么这样正确?

    f(m)=S(m)mod2f(m) = S(m) \bmod 2(即前缀和的奇偶性)。

    从递推:

    f(m)=(f(m1)+f(m/2))mod2f(m) = (f(m-1) + f(\lfloor m/2 \rfloor)) \bmod 2

    对于 m>nm > n,可以证明:

    • f(m)f(m) 的值只取决于 mm 的二进制表示和 f(n)f(n)
    • mm 足够大时,f(m)f(m) 呈现规律性

    标程中的循环就是在模拟这个“除以 22”的过程,每层检查奇偶性变化。


    六、示例验证

    以第一个测试用例为例:

    n=1, a=[1], l=1
    
    • nn 是奇数,不扩展
    • 计算 p=pref[1]&1=1p = pref[1] \& 1 = 1
    • get(1)x=12x=1 \le 2,返回 a[1]=1a[1]=1

    输出 1


    七、复杂度分析

    • 预处理:O(n)O(n)
    • 每次 get(x)O(logx)O(\log x),因为 xx 每次除以 22
    • 总复杂度:O(n+tlogl)O(n + t \log l),满足 n2×105n \le 2\times 10^5l1018l \le 10^{18}

    八、总结

    要点 说明
    核心思想 利用前缀异或的递推,将问题转化为奇偶性判断
    数学化简 通过扩展 2n2n 项和模 22 运算,避免递归
    算法步骤 1. 补全 nn 为奇数
    2. 扩展至 2n2n
    3. 用循环除以 22 计算答案
    时间复杂度 O(n+tlogl)O(n + t \log l)
    空间复杂度 O(n)O(n)
    • 1

    信息

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