SCU 4103 function(前缀处理+字典树)

A - function
Time Limit:0MS     Memory Limit:0KB     64bit IO Format:%lld & %llu

Description

Time Limit: 8000 MS    Memory Limit: 131072 K 
    
    

Description

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 5

Sample Output

1 1

Source

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值