给你n个数,然后给你m组询问,每组询问给你一个数,输出n个数中与该数亦或
的最大的那个数,输出的是被亦或的那个数,不是亦或后的结果。
思路:
我用的是字典树+贪心,首先我们可以把前n个数拆成2进制,然后补全前导0,
我是补成了34位,然后把他存在字典树中,对于每个询问,把他变成二进制,然后补全前导0,然后在把每一位都取反,在字典树上查找,查找的时候用贪心的思想,因为前面的是高位,所以相等就走相等的,不行再走不相等的那个,反正都是34位,怎么走都有路,一直找到最后,在某一位上如果当前这一位一样了,那么sum += 当前这一位的权值(2^**),然后return sum,输出的时候不能直接输出sum求的是被异或的那个值,所以输出 sum ^ num,根据的是 a ^ b ^ a = b,还有一点要注意的就是一开始超时了,后来把 %2 改成 &1就400+ ms AC了.
#include<stdio.h> #include<string.h> #include<stdlib.h> typedef struct Tree { Tree *next[2]; }Tree; Tree root; void Buid_Tree(char *str) { int len = 34; Tree *p = &root ,*q; for(int i = 0 ;i < len ;i ++) { int id = str[i] - '0'; if(p -> next[id] == NULL) { q = (Tree *) malloc(sizeof(root)); for(int j = 0 ;j < 2 ;j ++) q -> next[j] = NULL; p ->next[id] = q; p = p -> next[id]; } else p = p -> next[id]; } } __int64 Find(char *str) { int len = 34; Tree *p = &root; __int64 K = 2; K <<= 32; __int64 sum = 0; for(int i = 0 ;i < len ;i ++) { int id = str[i] - '0'; if(p -> next[id] == NULL) p = p -> next[id ^ 1]; else { p = p -> next[id]; sum += K; } K = K / 2; } return sum; } void get_str(char *str ,__int64 num) { int t = 34; str[t] = ' '; while(num) { str[--t] = (num & 1) + '0'; num >>= 1; } for(int i = t - 1 ;i >= 0 ;i --) str[i] = '0'; } int main () { int i ,t ,n ,m ,cas = 1; __int64 num; char str[50]; scanf("%d" ,&t); while(t--) { scanf("%d %d" ,&n ,&m); root.next[0] = root.next[1] = NULL; while(n--) { scanf("%I64d" ,&num); get_str(str ,num); Buid_Tree(str); } printf("Case #%d: " ,cas ++); while(m--) { scanf("%I64d" ,&num); get_str(str ,num); for(i = 0 ;i < 34 ;i ++) if(str[i] == '1') str[i] = '0'; else str[i] = '1'; printf("%I64d " ,Find(str) ^ num); } } return 0; }