D. XOR Construction
D. XOR Construction
You are given integers .
Your task is to construct an array such that:
- every integer from to appears in exactly once;
- for every from to , (where denotes the bitwise XOR operator).
Input
The first line contains one integer ().
The second line contains integers ().
Additional constraint on the input: it's always possible to construct at least one valid array from the given sequence .
Output
Print integers . If there are multiple such arrays, you may print any of them.
Examples
input
4
2 1 2
output
0 2 3 1
input
6
1 6 1 4 1
output
2 3 5 4 0 1
解题思路
我的做法跟官方的基本一样。最关键的地方是要观察出 其实就是 的差分数组,假设下标都从 开始,即有 。主要是如果看到有 或者 就要想到对 求前缀和就会得到 。
然而我们现在还不知到 ,假设 ,,如果知道 的话那么整个 数组都确定下来了,就是 异或每个 。所以很自然想到枚举 来找到合法 ,使得 与每个 恰好是 的全排列。如果直接暴力验证的话时间复杂度就是 ,注意到题目保证存在解,所以可以分析一下 具有什么性质。
首先 一定是成对不同的,否则假设 ,那么不管 取什么必然有 ,因此不可能存在解,矛盾。由于 成对不同的,意味着 也是成对不同的,所以如果 ,那么此时 一定是 的全排列,此时的 就是合法的解。
为了快速得到 与这些 异或后的最大值是多少,可以将 存到 trie 中,然后从最高位开始贪心选择即可。
AC 代码如下,时间复杂度为 :
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
int a[N];
int tr[N * 19][2], idx;
void add(int x) {
int p = 0;
for (int i = 18; i >= 0; i--) {
int t = x >> i & 1;
if (!tr[p][t]) tr[p][t] = ++idx;
p = tr[p][t];
}
}
int query(int x) {
int p = 0, ret = 0;
for (int i = 18; i >= 0; i--) {
int t = x >> i & 1;
if (tr[p][!t]) {
p = tr[p][!t];
ret |= 1 << i;
}
else {
p = tr[p][t];
}
}
return ret;
}
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int x;
scanf("%d", &x);
a[i] = a[i - 1] ^ x;
add(a[i]);
}
add(0);
for (int i = 0; i < n; i++) {
if (query(i) < n) {
for (int j = 0; j < n; j++) {
printf("%d ", a[j] ^ i);
}
break;
}
}
return 0;
}
再提供另外一种思路,按位考虑每一个 。对于二进制的第 位,如果每个 的第 位共有 个 ,数字 的第 位共有 个 ,由于题目保证有解,因此如果 ,那么只需让 的第 位为 即可,否则为 。
AC 代码如下,时间复杂度为 :
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
int a[N];
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int x;
scanf("%d", &x);
a[i] = a[i - 1] ^ x;
}
int ret = 0;
for (int i = 0; i <= 18; i++) {
int s = 0;
for (int j = 0; j < n; j++) {
s += j >> i & 1;
s -= a[j] >> i & 1;
}
if (s) ret |= 1 << i;
}
for (int i = 0; i < n; i++) {
printf("%d ", a[i] ^ ret);
}
return 0;
}
参考资料
Educational Codeforces Round 157 Editorial:https://codeforces.com/blog/entry/122034
Educational Codeforces Round 157 (Rated for Div. 2):https://zhuanlan.zhihu.com/p/665022975
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17810705.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效