异或

给定整数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

思路:Brute force肯定TLE,套路肯定是按照一位一位来算

后考虑按位递归,同时对数组进行分类

/*
 * 还是TLE
 * 因为这里涉及到了前缀和一位一位的比较
 * 很自然想到了Trie,用Trie树优化一下这个过程??
 * 但是这里递归的花销是出在哪呢?是每次都要加到一个List花销大了?
 */
public class TLE2 {
	
	static int ret = 0;
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt(), m = sc.nextInt();
		int[] a = new int[n];
		for(int i=0; i<n; i++)a[i]=sc.nextInt();
		ret = 0;
		
		List<Integer> s = new LinkedList<Integer>();
		for(int i : a)	s.add(i);
		get(a, s, 17, m);
		System.out.println(ret);
	}

	public static void get(int[] a, List<Integer> s, int bit, int m) {
		List<Integer> s1 = new LinkedList<Integer>(), s0 = new LinkedList<Integer>();
		int t = (1<<bit);
		for(int i : s) {
			if((i & t) != 0)	s1.add(i);
			else	s0.add(i);
		}
		
		if(t > m) {
			ret += s1.size() * s0.size();
			get(a, s1, bit-1, m);
			get(a, s0, bit-1, m);
			
		} else if((t & m) == t){
			int tmp = 0;
			for(int i : s0)
				for(int j : s1)
					if((i^j) > m)
						tmp ++;
			ret += tmp;
		}
	}
}


TLE,估计是复制数这一部分开销太大,因为这里涉及到了前缀和一位一位的比较
 * 很自然想到了Trie,用Trie树优化

因为不用新建List添加数字,建树完保持了原有的数据信息

build,在search,遍历一遍数组进行search,这样就可以确定每一步要走的方向

package l5;

import java.util.Scanner;

/*
 * Trie树优化,不要新建List添加数字
 */
public class Main {
	
	static long ret = 0;
	
	static class Trie {
		Trie[] next = new Trie[2];
		int[] cnt = new int[2];
	}
	
	public static void main(String[] args) {
		ret = 0;
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt(), m = sc.nextInt();
		int[] a = new int[n];
		int max = Integer.MIN_VALUE;
		for(int i=0; i<n; i++) {
			a[i]=sc.nextInt();
			max = Math.max(max, a[i]);
		}
		int bits = 31;
		while((max & (1<<bits)) == 0)	bits--;
		
		Trie root = new Trie();
		for(int i : a)
			buildTrie(root, i, bits);
		
		for(int i : a) 
			search(root, i, m, bits);
		
		System.out.println(ret/2);
	}

	private static void search(Trie root, int i, int m, int bits) {
		if(bits == -1 || root == null)	return;
		int t = (1 << bits), bit = ((i>>bits) & 1);
		if(t > m) {
			ret += root.cnt[(1^bit)];
			search(root.next[bit], i, m, bits-1);
			
		} else {
			search(root.next[(1^bit)], i, m-t, bits-1);
			
		}
	}

	private static void buildTrie(Trie root, int i, int bits) {
		if(bits == -1)	return;
		int bit = ((i>>bits) & 1);
		if(root.next[bit] == null)
			root.next[bit] = new Trie();
		root.cnt[bit] ++;
		buildTrie(root.next[bit], i, bits-1);
	}

}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值