CF1658 D1 & D2 388535 (TWO Version) (V1:二进制, V2:01trie)
对于第一个版本,l固定为0:
对于每一位,观察1到8的二进制,在0-r的前缀中0的个数一定大于等于1的个数。 所以我们只需要统计每一位中 1,0 的个数,如果 1的个数大于 0,x位就必须为 1.相同情况下1|0都可以,他只是让顺序变了。
对于第一个版本,l>=0:
上面的规律就不适用了。
- 存在一个i使得ai ^ x = l,则枚举l ^ai 找到x
- x ^ ai 得到的最大值等于r,最小值等于l时候这个x可行。因为ai是由l到r变来的,所以ai 异或同一个x一定不同,所以只用判最大最小值。
版本二答案:
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0)
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
const int N = 2e5 + 5;
const int M = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
int a[N], tot = 1, trie[N * 20][2];
void insert(int x) {
int p = 1;
for( int i = 16; i >= 0; -- i) {
bool k = x >> i & 1;
if(!trie[p][k]) trie[p][k] = ++ tot;
p = trie[p][k];
}
}
int askmax(int x) {
int p = 1, res= 0;
for ( int i = 16; i >= 0; -- i ) {
bool k = x >> i & 1;
if(trie[p][!k]) res = res << 1 | 1, p = trie[p][!k];
else res = res << 1 | 0, p = trie[p][k];
}
return res;
}
int askmin(int x) {
int p = 1, res= 0;
for ( int i = 16; i >= 0; -- i ) {
bool k = x >> i & 1;
if (trie[p][k]) res = res << 1 | 0, p = trie[p][k];
else res = res << 1 | 1, p = trie[p][!k];
}
return res;
}
void init() {
memset(trie, 0, sizeof (int) * 2 * (tot + 1)), tot = 1;
}
void solve() {
int l, r, x; cin >> l >> r;
init();
for ( int i = l; i <= r; ++ i ) cin >> a[i], insert(a[i]);
int mx, mn, ans = -1;
for ( int i = l; i <= r; ++ i) {
mx = askmax(l ^ a[i]), mn = askmin(l ^ a[i]);
if(mx == r && mn == l) {
cout << (l ^ a[i]) << endl;
return;
}
}
}
int main() {
int t; cin >> t;
while ( t -- ) solve();
return 0;
}