题目描述
给定整数m以及n个数字A1, A2, …, An,将数列A中所有元素两两异或,共能得到n(n-1)/2个结果。请求出这些结果中大于m的有多少个。
思路
将数组的每个数的二进制insert到单词树中,单词树的每个节点维护一个count,记录到当前节点的数字的个数
到单词树中查找数组的每个数字,从最高位开始与tar比较,讨论:
如果数字当前位为1,tar该位为1,则访问节点代表0的子节点
后面的逻辑很简单,不举例了
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| import java.util.Scanner;
class TrieNode{ TrieNode[]next = new TrieNode[2]; int count = 0; int digit = 0; public TrieNode(int digit){ this.digit = digit; } }
public class Main { public static void insert(TrieNode root, int number){ TrieNode prev = root; for(int i = 31; i >= 0; i--){ int digit = (number >> i) & 1; if(prev.next[digit] == null){ prev.next[digit] = new TrieNode(digit); } prev = prev.next[digit]; prev.count++; } } public static int query(TrieNode root, int a, int m, int k){ if(root == null){ return 0; } TrieNode prev = root; for(int i = k; i >= 0; i--){ int mDigit = (m >> i) & 1; int aDigit = (a >> i) & 1; if(mDigit == 1 && aDigit == 1){ if(prev.next[0] == null){ return 0; } else{ prev = prev.next[0]; } } else if(mDigit == 1 && aDigit == 0){ if(prev.next[1] == null){ return 0; } else{ prev = prev.next[1]; } } else if(mDigit == 0 && aDigit == 0){ return query(prev.next[0], a, m, i-1) + (prev.next[1] == null ? 0 : prev.next[1].count); } else if(mDigit == 0 && aDigit == 1){ return query(prev.next[1], a, m, i-1) + (prev.next[0] == null ? 0 : prev.next[0].count); } } return 0; } public static void main(String[] args) { TrieNode root = new TrieNode(-1); Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int m = sc.nextInt(); int[]array = new int[n]; for(int i = 0; i < n; i++){ array[i] = sc.nextInt(); insert(root, array[i]); } long result = 0; for(int number : array){ result += query(root, number, m, 31); } System.out.println(result / 2); } }
|
考差点