题目链接

完美异或

题目描述

给定一个整数 ,需要构造一个长度为 的数组 ,该数组被称为“伟大数组”如果满足以下所有条件:

  1. 数组 是单调非降的()。
  2. 所有元素 都是非负整数。
  3. 数组的异或和 的一个因子(即 )。

如果存在这样的数组,输出任意一个;如果不存在,则输出 -1。

解题思路

这是一个构造性的问题。我们需要找到一种方法来构建一个满足所有三个条件的数组。

最棘手的条件是异或和 必须是 的因子。为了简化这个问题,我们可以尝试构造一个数组,使其异或和 是一个特定的、容易满足整除条件的值。一个绝佳的选择是 ,因为 是任何正整数 的因子。

这样,问题就转化为:构造一个长度为 的非降、非负整数数组,使其异或和为

我们可以利用异或运算的性质 a \oplus a = 0 来抵消大部分元素,从而精确地控制最终的异或和。我们可以根据 的奇偶性来分情况讨论:

情况一: 是奇数

  • 。我们可以让数组中大量的元素成对出现以使它们的异或和为 0。
  • 我们构造 个(一个偶数)相同的元素。例如,前 个元素都设为 。它们的异或和是
  • 为了让整个数组的异或和为 ,我们只需要让最后一个元素 满足 ,所以
  • 这样构造出的数组为 (包含 )。
  • 验证条件:
    1. 非降:,满足。
    2. 非负:所有元素都非负,满足。
    3. 异或和: 的因子,满足。
  • 对于 的特殊情况,此构造给出数组 ,异或和为 ,也满足。

情况二: 是偶数

  • 。我们不能像奇数情况那样只用一个不同的数,因为 是奇数,无法简单地用相同元素抵消。
  • 我们可以让前 个元素(一个偶数)相同来抵消。同样,我们将它们设为 。它们的异或和为
  • 现在我们需要设置最后两个元素 ,使得它们的异或和为 (即 ),并且满足非降条件 ()。
  • 有很多数对满足异或和为 ,例如 等。
  • 我们需要找到一对 使得
  • 选择 满足
  • 这样构造出的数组为 (包含 )。
  • 验证条件:
    1. 非降:,满足。
    2. 非负:所有元素都非负,满足。
    3. 异或和: 的因子,满足。

综上所述,我们找到了一种对所有 都有效的构造方法,因此不存在无解的情况。

代码

#include <iostream>

void solve() {
    int n;
    std::cin >> n;
    if (n % 2 != 0) { // n 是奇数
        for (int i = 0; i < n - 1; ++i) {
            std::cout << "0 ";
        }
        std::cout << "1\n";
    } else { // n 是偶数
        for (int i = 0; i < n - 2; ++i) {
            std::cout << "0 ";
        }
        std::cout << "2 3\n";
    }
}

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);
    int t;
    std::cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int t = Integer.parseInt(br.readLine());
        StringBuilder sb = new StringBuilder();
        while (t-- > 0) {
            int n = Integer.parseInt(br.readLine());
            if (n % 2 != 0) { // n 是奇数
                for (int i = 0; i < n - 1; i++) {
                    sb.append("0 ");
                }
                sb.append("1\n");
            } else { // n 是偶数
                for (int i = 0; i < n - 2; i++) {
                    sb.append("0 ");
                }
                sb.append("2 3\n");
            }
        }
        System.out.print(sb.toString());
    }
}
import sys

def solve():
    n_str = sys.stdin.readline()
    if not n_str:
        return
    n = int(n_str)
    
    if n % 2 != 0: # n 是奇数
        arr = ["0"] * (n - 1) + ["1"]
    else: # n 是偶数
        arr = ["0"] * (n - 2) + ["2", "3"]
    
    sys.stdout.write(" ".join(arr) + "\n")

def main():
    t_str = sys.stdin.readline()
    if not t_str:
        return
    t = int(t_str)
    for _ in range(t):
        solve()

if __name__ == "__main__":
    main()

算法及复杂度

  • 算法:构造法。根据 的奇偶性,我们直接构造并输出一个满足条件的数组,其异或和恒为
  • 时间复杂度:对于每个测试用例,我们需要循环 次来输出数组元素。由于所有测试用例的 之和有上限,设为 ,则总时间复杂度为
  • 空间复杂度:我们不需要存储整个数组,可以直接在循环中输出,因此只需要常数级别的额外空间,即