C Tokitsukaze and Min-Max XOR
题目大意
- 给定一个数组

- 从
任取数构成序列
- 序列
满足
,(可以只取一个数) - 问能构造出多少个


解题思路
- 定
找
- 双枚举时间复杂度到
,考虑利用
加速统计
的方案
,即将数字按二进制位拆分挂在树上- 对于一个数,它在树上经过的点,均加上它对答案的贡献
- 所以树上的某一点存的信息为,以这个点的数位为分界,在它之前(包括它)均为某固定值,而在它后均为任意值的数对答案的贡献
- 若当前值为
,令其为
,则小于
的有
个,不考虑限制的话,共有
种选取
的方式 - 若选取了
作为
,则
均确定了是否选取 - 所以
,方案数为
- 若在
上,当前为第
位,则前
位均与
对应数位相同 - 若
的第
位为
,且
存在着与
的第t位相同的点 - 则
与该点往下的所有值异或后,第
位均为
- 答案加上该点值,即

- 不必在从该点往下走挨个统计,实现了加速
- 若能在
上走到最后,则存在
,答案加上该点值 - 最后处理完了
,在将其加入
- 由于
数组长度可以为
,所以初始
- 最终复杂度为

- 注意
上为
import java.io.*;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.Vector;
public class Main{
static long md=(long)1e9+7L;
static long qm(long a,long b) {
long res=1;
while(b>0) {
if((b&1)==1)res=(res*a)%md;
a=a*a%md;
b>>=1;
}
return res;
}
static
class Trie{
long[] cnt;//一个数分成32位,共32层,最后一层最多为n
int[][] tr;//01trie
int t;
public Trie(int n) {
cnt=new long[n*32];
tr=new int[n*32][2];
t=0;
}
void insert(int x,long y) {
int p=0;
for (int i = 31; i >= 0; i--) {
int j=(x>>i)&1;
if(tr[p][j]==0) {
t++;
tr[p][j]=t;
}
p=tr[p][j];
cnt[p]=(cnt[p]+y)%md;//在沿途放上,便于统计小于k的情况
}
}
long query(int x,int k) {
long res=0;
int p=0;
for (int i = 31; i >= 0; i--) {
int xt=(x>>i)&1;
int kt=(k>>i)&1;
if(kt==1&&tr[p][xt]!=0) {
res=(res+cnt[tr[p][xt]])%md;
//统计i^j<k
}
if(tr[p][xt^kt]==0) {
return res;
//不能满足前t-1位,i^j=k
}
p=tr[p][xt^kt];
}
res=(res+cnt[p])%md;
//i^j=k的情况
return res;
}
}
public static void main(String[] args) throws IOException{
AReader input=new AReader();
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int T=input.nextInt();
while(T>0) {
int n=input.nextInt();
int k=input.nextInt();
int[] a=new int[n+1];
for(int i=1;i<=n;++i)a[i]=input.nextInt();
Arrays.sort(a,1,n+1);
Trie Tp=new Trie(n+1);
long ans=n;//min=i,max=j,i=j的情况
for(int i=1;i<=n;++i) {
//此时trie上的数均小于a[i]
int x=a[i];
ans=(ans+Tp.query(x, k)*qm(2, i-1)%md)%md;
long inv=qm(qm(2L, i), md-2);
Tp.insert(x, inv);
}
out.println(ans);
T--;
}
out.flush();
out.close();
}
static
class AReader{
BufferedReader bf;
StringTokenizer st;
BufferedWriter bw;
public AReader(){
bf=new BufferedReader(new InputStreamReader(System.in));
st=new StringTokenizer("");
bw=new BufferedWriter(new OutputStreamWriter(System.out));
}
public String nextLine() throws IOException{
return bf.readLine();
}
public String next() throws IOException{
while(!st.hasMoreTokens()){
st=new StringTokenizer(bf.readLine());
}
return st.nextToken();
}
public char nextChar() throws IOException{
//确定下一个token只有一个字符的时候再用
return next().charAt(0);
}
public int nextInt() throws IOException{
return Integer.parseInt(next());
}
public long nextLong() throws IOException{
return Long.parseLong(next());
}
public double nextDouble() throws IOException{
return Double.parseDouble(next());
}
public float nextFloat() throws IOException{
return Float.parseFloat(next());
}
public byte nextByte() throws IOException{
return Byte.parseByte(next());
}
public short nextShort() throws IOException{
return Short.parseShort(next());
}
public BigInteger nextBigInteger() throws IOException{
return new BigInteger(next());
}
public void println() throws IOException {
bw.newLine();
}
public void println(int[] arr) throws IOException{
for (int value : arr) {
bw.write(value + " ");
}
println();
}
public void println(int l, int r, int[] arr) throws IOException{
for (int i = l; i <= r; i ++) {
bw.write(arr[i] + " ");
}
println();
}
public void println(int a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
public void print(int a) throws IOException{
bw.write(String.valueOf(a));
}
public void println(String a) throws IOException{
bw.write(a);
bw.newLine();
}
public void print(String a) throws IOException{
bw.write(a);
}
public void println(long a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
public void print(long a) throws IOException{
bw.write(String.valueOf(a));
}
public void println(double a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
public void print(double a) throws IOException{
bw.write(String.valueOf(a));
}
public void print(char a) throws IOException{
bw.write(String.valueOf(a));
}
public void println(char a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
}
}