1 条题解

  • 0
    @ 2026-5-17 23:24:39

    题意

    给定一个长度为 n=2kn = 2^k 的数组 aa(下标从 00n1n-1)。
    每次操作同时将所有元素替换为:

    ai=aia(i+1)modna_i = a_i \oplus a_{(i+1) \bmod n}

    重复操作直到数组全为零。求最少操作次数,若永远不能全零则输出 1-1


    关键观察

    11. 操作的本质

    定义变换 TT

    T(a)i=aiai+1T(a)_i = a_i \oplus a_{i+1}

    下标模 nn,所有 ii 同时更新。

    这是一个线性变换(在 F2\mathbb{F}_2 上),且具有很好的结构。


    22. 分治性质

    由于 nn22 的幂,数组可以不断对半分割。

    设当前数组长度为 lenlenlenlen22 的幂)。
    考虑将其分成前后两半:

    $$L = [a_0, a_1, \dots, a_{len/2-1}], \quad R = [a_{len/2}, a_{len/2+1}, \dots, a_{len-1}] $$

    进行一次操作后,观察新数组的前半部分:

    $$b_i = a_i \oplus a_{i+len/2} \quad (0 \le i < len/2) $$

    这正是 LLRR 的对应位置异或。


    33. 决策分支

    • 如果 L=RL = R(即 ai=ai+len/2a_i = a_{i+len/2} 对所有 ii 成立),则 bi=0b_i = 0,此时后半部分在操作后变为 00(因为 $a_{i+len/2} \oplus a_{i+len/2+1} = a_i \oplus a_{i+1}$,恰好与前半部分相同)。实际上,此时问题可以缩小一半:只需对 LL 继续操作即可,因为 RR 会与 LL 同步变化。

    • 如果 LRL \ne R,则 bb 非零,并且可以证明,经过 len/2len/2 次操作后,数组会变为 [b0,b1,,blen/21,0,0,,0][b_0, b_1, \dots, b_{len/2-1}, 0, 0, \dots, 0] 的形式(后半全零)。此时问题转化为对长度为 len/2len/2 的数组 bb 继续操作,且已经花费了 len/2len/2 步。


    44. 递归/迭代算法

    11. 若当前数组全为零,返回 0022. 若 len=1len = 1:因为 a0=a0a0=0a_0 = a_0 \oplus a_0 = 0,一次操作即可,返回 1133. 否则:

    • 计算 bi=aiai+len/2b_i = a_i \oplus a_{i+len/2}0i<len/20 \le i < len/2)。
    • 如果所有 bi=0b_i = 0(即 L=RL = R):
      • 则只需递归处理长度为 len/2len/2LL
    • 否则:
      • 花费 len/2len/2 步,然后递归处理长度为 len/2len/2bb44. 最后若 a[0]0a[0] \ne 0,还需额外一步(对应 len=1len=1 的情况)。

    55. 正确性说明

    • L=RL = R 时,操作 len/2len/2 次后数组会变为全零?不对,实际上每次操作会同时更新 LLRR,但由于 L=RL=R,它们始终保持相等,且每次操作相当于对 LL 自身做一次变换(因为 ai+len/2=aia_{i+len/2} = a_i)。因此,LL 独立演化,RR 作为其副本。所以问题规模减半,且无需额外步数。
    • LRL \ne R 时,经过 len/2len/2 次操作后,后半部分变为全零,前半部分变为 bb。这 len/2len/2 步是必须花费的。
    • 最终当长度为 11 时,若该元素非零,则再花 11 步使其变为零。

    示例验证

    样例 11

    n=4, a=[1,2,1,2]n=4,\ a=[1,2,1,2]

    • len=4len=4L=[1,2],R=[1,2]L=[1,2], R=[1,2],相等 → 长度减半为 22a=[1,2]a=[1,2]
    • len=2len=2L=[1],R=[2]L=[1], R=[2],不等 → b=[12=3]b=[1\oplus2=3],步数 +=1+=1a=[3]a=[3]
    • len=1len=1a[0]=30a[0]=3\ne0 → 步数 +=1+=1 总步数 =2=2

    样例 22

    全零 → 输出 00

    样例 33

    n=1, a=[14]n=1,\ a=[14] → 输出 11

    样例 44

    n=8, a=[0,1,2,3,4,5,6,7]n=8,\ a=[0,1,2,3,4,5,6,7] 模拟可得步数 =5=5


    复杂度

    每次循环长度减半,总操作 O(nlogn)O(n \log n)n220n \le 2^{20} 可过。


    完整代码

    #include <bits/stdc++.h>
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        
        int n;
        cin >> n;
        vector<int> a(n);
        for (int i = 0; i < n; i++) {
            cin >> a[i];
        }
        
        // 检查是否全零
        bool allZero = true;
        for (int x : a) {
            if (x != 0) {
                allZero = false;
                break;
            }
        }
        if (allZero) {
            cout << "0\n";
            return 0;
        }
        
        // 特判 n=1
        if (n == 1) {
            cout << "1\n";
            return 0;
        }
        
        int steps = 0;
        int len = n;
        while (len > 1) {
            vector<int> b(len / 2);
            bool equal = true;
            for (int i = 0; i < len / 2; i++) {
                b[i] = a[i] ^ a[i + len / 2];
                if (b[i] != 0) equal = false;
            }
            if (equal) {
                // 两半相等,缩小问题
                a.resize(len / 2);
                len /= 2;
            } else {
                // 需要一次完整操作
                steps += len / 2;
                a = move(b);
                len /= 2;
            }
        }
        
        // 最后还剩一个元素
        if (a[0] != 0) steps++;
        
        cout << steps << "\n";
        
        return 0;
    }
    
    • 1

    信息

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