题解 CF1895D XOR Construction

作为一个 Div. 2 的 D 题,不是很难的题。

题意

标签:字典树,贪心。

给你 $n-1$ 个正整数 $a_1,a_2,\dots,a_{n-1}$。

你需要构造一个序列 $b_1,b_2,\dots,b_n$ 满足下列要求:

  • $0 \sim n-1$ 中的每个整数刚好在 $b$ 中出现一次。
  • $\forall i\in [1,n) \cap \mathbb{N}^{*},b_i \oplus b_{i+1} = a_i$。

输出任意一组解即可,保证有解。

分析

设 $s_i = a_1 \oplus a_2 \oplus \dots \oplus a_i$。

于是 $b_i = b_1 \oplus a_1 \oplus a_2 \oplus \dots \oplus a_i = b_1 \oplus s_{i-1}$。

保证有解很显然的一个性质是 $\forall i \in [1,n),s_i \neq 0$。

如果 $s$ 存在一个值为 $0$,就会导致 $b$ 数组中会有两个元素相同,将不满足每个数刚好出现一次。

数字重复出现我们就不需要考虑了,接下来需要考虑 $b$ 的范围。

下界是很容易满足的,只要 $b_1 \ge 0$,那么 $b$ 都会大于等于 $0$。

接下来考虑上界,第一个条件要让 $b_i < n$ 恒成立,其实就是让 $(b_1 \oplus s_{i-1})_{\max} < n$ 恒成立。

所以说直接枚举 $b_1 \in [0,n)$,利用字典树可以在 $O(\log n)$ 的时间内求出 $(b_1 \oplus s_{i-1})_{\max}$,判断如果符合条件直接输出就行了。

时间复杂度 $O(n \log n)$,空间复杂度 $O(n \log n)$。

代码

//the code is from chenjh
#include<cstdio>
#define MAXN 200002
using namespace std;
int n;
int a[MAXN];
int tot=1,trie[MAXN<<5][2];//字典树空间要开够。
void ins(const int x){//字典树插入。
    int u=1;
    for(int i=20;i>=0;i--){
        bool v=(x>>i)&1;
        if(!trie[u][v]) trie[u][v]=++tot;
        u=trie[u][v];
    }
}
int ask(const int x){//查找和 x 异或能得到最大值的数。
    int u=1,ret=0;
    for(int i=20;i>=0;i--){
        bool v=(x>>i)&1;
        if(trie[u][v^1]) u=trie[u][v^1],ret|=(v^1)<<i;
        else if(trie[u][v]) u=trie[u][v],ret|=v<<i;
    }
    return ret;
}
int main(){
    scanf("%d",&n);
    for(int i=2;i<=n;i++) scanf("%d",&a[i]),a[i]^=a[i-1],ins(a[i]);//直接前缀和,省去 s 数组。
    for(int b=0;b<n;b++)if((b^ask(b))<n){//满足上界,直接输出答案。
        for(int i=1;i<=n;i++) printf("%d ",b^a[i]);
        return 0;
    }
    return 0;
}
posted @ 2023-11-05 19:56  Chen_Jinhui  阅读(26)  评论(0)    收藏  举报  来源