Description
Time Limit: 8000 MS Memory Limit: 131072 KDescription
Given a set of n integers: num={num1,num2,.....,num n} and an integer m. we define a function AA(num,m) as below: AA(num,m)={[l,r]| (l<=r) && (num[l]^num[l+1]….^num[r])<=m }. Your task is to calculate the number of element of AA(num,m).Input
The first line contains the number of test cases. For every test,the input consists of two lines. The first line contains two integers n and m. There are n integers in the second line. limit:1<=n<=10^5, 0<=num[i], m<2^31;Output
For each test case just output one integer in one line.Sample Input
2 2 3 1 4 2 3 4 5Sample Output
1 1Source
456@scuacm Sichuan University Programming Contest 2012 Preliminary
题意:给定n个数,问有多少个区间【l,r】里面所有数异或的结果小于m
题解:字典树,对于区间[L,R]的异或值,是满足区间减法的。即a[L] ^ a[L + 1] ^ ... ^ a[R] = (a[1] ^ a[2] ^ .. ^ a[L - 1]) ^ (a[1] ^ a[2] ^ .. ^ a[R]) (因为a[1]... a[L - 1]全部出现了2次,根据异或性质,是抵消的)。所以将a[1] ^ ... a[i]的结果插入trie树中,类似于前缀和的形式,每次对于一个新的a[i + 1],查询a[1],(a[1] ^ a[2]) .. (a[1] ^ .. ^ a[i])有多少个与现在 (a[1] ^ .. ^ a[i+1])异或结果<=M
#include<stdio.h>
struct tire{
int next[2],cou;
void init()
{
cou=0;
next[0]=next[1]=-1;
}
}tree[3200008];
int all,n,m;
void myinsert(int x)
{
int id=0,i,temp;
for(i=30;i>=0;i--)
{
tree[id].cou++;
temp=(1<<i)&x?1:0;
if(tree[id].next[temp]==-1)
{
tree[++all].init();
tree[id].next[temp]=all;
}
id=tree[id].next[temp];
}
tree[id].cou++;
}
int myfind(int now,int cur,int id)
{
int temp=0;
if(!cur) return now<=m?tree[id].cou:0;
if((now|((1<<cur)-1))<=m) return tree[id].cou;
if((now&(~((1<<cur)-1)))>m) return 0;
if(tree[id].next[0]!=-1) temp+=myfind(now,cur-1,tree[id].next[0]);
if(tree[id].next[1]!=-1) temp+=myfind(now^(1<<(cur-1)),cur-1,tree[id].next[1]);
return temp;
}
int main()
{
int t,i,now,x;
long long res;
scanf("%d",&t);
while(t--)
{
tree[all=0].init();
scanf("%d%d",&n,&m);
myinsert(0);
for(res=now=i=0;i<n;i++)
{
scanf("%d",&x);
now^=x;
res+=myfind(now,31,0);
myinsert(now);
}
printf("%I64d\n",res);
}
return 0;
}