给定整数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;
}
}
}
* 很自然想到了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);
}
}