感觉好猛的一道异或题

题目描述
给定整数m以及n各数字A1,A2,..An,将数列A中所有元素两两异或,共能得到n(n-1)/2个结果,请求出这些结果中大于m的有多少个。
输入描述:
第一行包含两个整数n,m. 

第二行给出n个整数A1,A2,...,An。

数据范围

对于30%的数据,1 <= n, m <= 1000

对于100%的数据,1 <= n, m, Ai <= 10^5
输出描述:
输出仅包括一行,即所求的答案

示例1
输入

3 10  
6 5 10

输出

2


用双层循环嵌套直接做只A了60%,在讨论区学习了字典树的思路:
从高位向下比较:
1)如果x高位为1,而m高位为1,则比较字典树高位为0的分支继续向下;
2)如果x高位为1,m高位为0,则这种情况的数量为字典树高位为0的数量+字典树高位为1的分支继续向下比较;
3)如果x高位为0,m高位为1,则比较字典树高位为1的分支继续向下;
4)如果x高位为0,m高位为0,则这种情况数量为字典树高位为1的数量+字典树高位为0的分支继续向下比较;

import java.util.Scanner;


public class Xor {
	public static int index = 18;//因为范围是100000以内

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		while(in.hasNext()){
            int n = in.nextInt();
            int m = in.nextInt();
            int [] arr = new int [n];
            
            for(int i = 0; i < n; ++i){
                arr[i] = in.nextInt();
            }
            System.out.println(solve(n,m,arr));
        }
	}
	
	public static long solve(int n, int m, int [] arr){
		dicTree myRoot = new Xor().buildTree(n, m, arr);
		
		long res = 0;
		for(int i = 0; i < n; ++i){
			res += getRes(arr[i], m, index, myRoot);
		}
		return res/2;
	}
	
	public static long getRes(int x, int m, int index, dicTree node){
		if(node == null) return 0;
		
		dicTree current = node;
		
		for(int i = index; i >=0; --i){
			int xi = (x>>i)&1;
			int mi = (m>>i)&1;
			if(xi == 1 && mi == 1){
				if(current.next[0] == null)
					return 0;
				current = current.next[0];
			}else if(xi == 0 && mi == 1){
				if(current.next[1] == null)
					return 0;
				current = current.next[1];
			}else if(xi == 1 && mi == 0){
				long left = current.next[0] == null?0:current.next[0].count;
				long right = getRes(x,m,i-1,current.next[1]);
				return left+right;
			}else if(xi == 0 && mi == 0){
				long left = current.next[1] == null?0:current.next[1].count;
				long right = getRes(x,m,i-1,current.next[0]);
				return left+right;
			}
		}
		return 0;
	}
	
	public dicTree buildTree(int n, int m, int [] arr){
		dicTree root = new dicTree();
		
		for(int i = 0; i < n; ++i){
			dicTree current = root;
			for(int k = index; k >=0; --k){
				int temp = (arr[i]>>>k)&1;
				if(current.next[temp] == null){
					current.next[temp] = new dicTree();
				}else{
					current.next[temp].count++;
				}
				current = current.next[temp];
			}
		}
		return root;
	}
}

class dicTree{
	dicTree [] next = new dicTree [2];
	int count = 1;
}

少年还是欠缺磨练,这题解思路自己就想不到。字典树字典树字典树记住了

你可能感兴趣的:(OJ,算法)