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;
}
posted @ 2022-03-28 16:19  qingyanng  阅读(18)  评论(0编辑  收藏  举报