Problem - D2 - Codeforces
题意:
给定一个区间[l, r]和r - l + 1个数,问是否存在一个数 x ,使得这些数异或上 x 之后为[l, r]的一个排列
思路:
这种有关一个集合和异或操作的,都可以试试字典树
我们将所有数插入到字典树中
首先一个结论:若两个数异或 x 不同,那么这两个数本来一定不同
因为这些数异或 x 之后是一个排列,因此这些数原来就不同
如果存在 x ,使得这些数的对 x 的最大异或为 r,最小异或为 l,那么就一定满足条件(因为这些数一定不同)
所以我们可以考虑枚举 x
但是 x 范围太大
注意到 x 一定满足某个ai使得
ai ^ x = l
但是是哪个 ai 异或了 x 变成 l不确定,所以可以转化成枚举 ai
这样 x = ai ^ l
还有个多样例清空01trie的技巧也可以学一下:
void init() {
tr[0][0] = tr[0][1] = 0;
tot = 0;
}
void insert(int x) {
int p = 0;
for (int j = 20; j >= 0; j --) {
int u = ((x >> j) & 1);
if (! tr[p][u]) {
tr[tot + 1][0] = tr[tot + 1][1] = 0;
tr[p][u] = ++tot;
}
p = tr[p][u];
}
tag[p] = x;
}
Code:
#include <bits/stdc++.h>
using i64 = long long;
using namespace std;
const int N = 5e5 + 10;
const int M = 3e6 + 10;
const int P = 131;
int l, r;
int tot = 0;
int a[N];
int tr[N * 30][2], tag[N];
void insert(int x) {
int p = 0;
for (int j = 20; j >= 0; j --) {
int u = ((x >> j) & 1);
if (! tr[p][u]) {
tr[tot + 1][0] = tr[tot + 1][1] = 0;
tr[p][u] = ++tot;
}
p = tr[p][u];
}
tag[p] = x;
}
int query_mx(int x) {
int p = 0;
for (int j = 20; j >= 0; j --) {
int u = ((x >> j) & 1);
if (tr[p][u ^ 1]) {
p = tr[p][u ^ 1];
}else {
p = tr[p][u];
}
}
return tag[p] ^ x;
}
int query_mi(int x) {
int p = 0;
for (int j = 20; j >= 0; j --) {
int u = ((x >> j) & 1);
if (tr[p][u]) {
p = tr[p][u];
}else {
p = tr[p][u ^ 1];
}
}
return tag[p] ^ x;
}
void init() {
tr[0][0] = tr[0][1] = 0;
tot = 0;
}
void solve() {
cin >> l >> r;
init();
for (int i = l; i <= r; i ++) {
cin >> a[i];
insert(a[i]);
}
for (int i = l; i <= r; i ++) {
int x = a[i] ^ l;
if (query_mi(x) == l && query_mx(x) == r) {
cout << x << "\n";
break;
}
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
cin >> t;
while(t --) {
solve();
}
return 0;
}