Vitya and Strange Lesson CodeForces - 842D
Trie+位运算
错误思路:
枚举数组里每一个数与询问的数异或,利用桶排序求最小值.时间复杂度O(n^2),TLE
正确思路:
想AC本题首先要明确几个性质:
- x^y^z = x^(y^z)
- 0~n位二进制数与n位二进制数异或的结果仍然在0~n位二进制数内,且不存在不同数取相同值的结果
- 3e5的二进制数大概在19位,在这19位以内每一个数除了数组内部都可能取到最小值
因此,求不在数组的最小值,就是求不在数组内的数字与询问的值异或的最小值,注意数字>3e5的也可能取到最小值,因为3e5!=1111...(19位)
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 const int N = 6e5+10; 5 int vis[N],son[N*2][2],idx; 6 void insert_t(int x) 7 { 8 int p = 0; 9 for(int i=31;~i;i--){ 10 int u = x>>i&1; 11 if(!son[p][u]) son[p][u] = ++idx; 12 p = son[p][u]; 13 } 14 } 15 int query(int x) 16 { 17 int p = 0,ans = 0; 18 for(int i=31;~i;i--){ 19 int u = x>>i&1; 20 if(!son[p][u]){ 21 ans+=(1<<i); 22 p = son[p][!u]; 23 }else p = son[p][u]; 24 } 25 return ans; 26 } 27 int main() 28 { 29 int n,m,t = 0; 30 scanf("%d%d",&n,&m); 31 for(int i=1;i<=n;i++){ 32 int x; scanf("%d",&x); 33 vis[x] = 1;//将进入数组的元素 标记 34 } 35 for(int i=0;i<=6e5;i++) 36 if(!vis[i]) insert_t(i); 37 for(int i=1;i<=m;i++){ 38 int x; scanf("%d",&x); 39 t = t^x; 40 printf("%d\n",query(t)); 41 } 42 return 0; 43 }