Codeforces Round #817 (Div. 4) G. Even-Odd XOR

Codeforces Round #817 (Div. 4)

翻译 岛田小雅

G. Even-Odd XOR

出题人 mesanu

给一个整型 \(n\),让你寻找一个由 \(n\) 个互不相同的非负整型组成的数组 \(a\),使得数组 \(a\) 中奇数下标的数和偶数下标的数分别进行异或运算结果相同。

输入格式

第一行是一个整型 \(t\) \((1≤t≤629)\), 代表测试点的个数。

接下来 \(t\) 行,每一行有一个整型 \(n\) \((3≤n≤2⋅10^5)\) ,代表数组大小。

数据保证 \(n\) 的总和不超过 \(2⋅10^5\).

输出格式

对于每个测试点,输出 \(n\) 个满足题意的互不相同的整型。

如果有很多解,输出其中任意一个。

样例

输入

7
8
3
4
5
6
7
9

输出

4 2 1 5 0 6 7 3
2 1 3
2 1 3 0
2 0 4 5 3
4 1 2 12 3 8
1 2 3 4 5 6 7
8 2 3 7 4 0 5 6 9

补充

第一个测试点中,奇数下标的数异或的结果是 \(4⊕1⊕0⊕7=2\) ,偶数下标的数异或的结果是 \(2⊕5⊕6⊕3=2\)

官方题解

作者 flamestorm

这道题有很多种解法,这里分享其中一个。

首先需要知道,如果我们能得到一个数组,让奇数下标的数和偶数下标的数分别进行异或的运算结果相同,那么所有数异或的结果必为 \(0\)。我们用 \(a\) 来表示所有奇数下标数的异或,用 \(b\) 来表示偶数下标数的异或,那么当且仅当 \(a = b\) 时,所有数字的异或结果为 \(0\)

问题是,要怎样生成一个数组,让它里面所有的数异或后结果为 \(0\) 呢?我们的第一反应也许是生成一个含有前面 \(n-1\) 个数字的数组,然后把最后一个数定为前面 \(n-1\) 个数的异或,以此来确保最后的结果为 \(0\)。但考虑到每个数字各不相同的条件,这个方法会遇到问题。进一步想,我们可以把前 \(n-2\) 个数先定下来,让它们都没有第 \(31\) 位的二进制,那么我们就能把第 \(n-1\) 个数直接设置成 \(2^{30}\),最后一个数也就能设置成前面所有数的异或,这样可以保证最后一个数在前 \(n-2\) 个数中完全没有出现过,因为在这之前的所有数都不存在第 \(31\) 位的二进制。接下来怎么保证最后两个数不同呢?事实上,只有前 \(n-2\) 个数的异或为 \(0\) 的时候,这种情况才会出现。我们只需要在前 \(n-2\) 个数中随便换个数字就可以了。

比如,如果 \(0,1,2...,n-4,n-3\) 的运算结果不是 \(0\),那挺好,我们就可以直接用最简单的方法得出答案。但是,如果运算结果是 \(0\),那我们就把其中一个数换成 \(n-2\),这两个序列总是有着不同的运算结果,所以它们可以总是保证结果不为 \(0\)

AC 代码

作者 岛田小雅
#include <bits/stdc++.h>
using namespace std;

int t, n;
int a = 1<<18; // 其实19位就够了
int check; // 存前n-2个数的XOR结果
bool f; // 用来记录数组{0,1,2,3...,n-4,n-3}的XOR结果是不是0,不是0为真,是0为假

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> t;
    while(t--)
    {
        cin >> n;
        check = 0;
        for(int i = 1; i < n-3; i++) check ^= i;
        if(check^n-3 == 0) check ^= n-2, f = false;
        else check ^= n-3, f = true;
        for(int i = 0; i < n-3; i++) cout << i << ' ';
        if(f) cout << n-3 << ' ';
        else cout << n-2 << ' ';
        cout << a << ' ' << (a^check) << '\n';
    }
    return 0;
}
posted @ 2022-09-17 23:40  岛田小雅  阅读(75)  评论(0编辑  收藏  举报