一道需要预处理优化的位运算

FJUT 2417
TimeLimit:2000MS MemoryLimit:128MB
给定一个序列 a1,a2……an

求有多少个对l,r(l<=r),满足 al ^ a(l+1) ^ a(l+2) ^…… ^ ar = s,其中^代表按位异或

Input
只有一组数据

第一行是一个整数n

接下来一行有n个整数,分别代表 a1,a2……an

再接下整数q代表查询次数

接来下来有q行,每行是一个整数代表s

其中0<n,s,ai<=10^6

q<=10

Output
对于每个s,输出有多少对l,r满足题目要求

SampleInput
4
2 2 4 1
7
1
2
3
4
5
6
7
SampleOutput
1
2
0
2
2
1
1

n的范围是10的六次方 暴力就10的是12次方了,而2S大概处理次数只有10的7次方,所以需要预处理一下。
然后ai的范围也是10的6次方,可以加上位运算异或的性质。考虑数组标记。
这里说一下位运算的两个重要性质。
1、x^0=x 一个数^0=它本身
2、x^x=0 一个数^它本身=0
3、如果a^b=c 那么a^c=b, b^c=a. 根据前两点可推.

那么题中的al ^ a(l+1) ^ a(l+2) ^…… ^ ar = s 就等于
al ^ a(l+1) ^ a(l+2) ^…… ^ ar ^0=s,
让0=( a1 ^ a2 ^…… ^ a(l-1) ) ^ ( a1 ^ a2 ^…… ^ a(l-1) )
进行交换就有
( a1 ^ a2 ^…… ^ ar) ^( a1 ^ a2 ^…… ^ a(l-1) )
也即
b[l-1] ^b[r]=s ,b[i]表示前i项异或和。
由性质三知道 s ^b[l-1]=b[r], s ^ b[r]=b[l-1].
那么我们只需要把前i项异或和存在数据b中,最后访问的时候直接看数组b中s ^b[i]有几个 求和即可,注意结果需要除以,因为计算了两次。
这里需要注意一点 让b【0】=1,想想为什么。。原因见文章末,
下面是代码。

#include<bits/stdc++.h>
using namespace std;
int a[1000005];
int b[2000000];

int main()
{
    int n,i,t,q;
   a[0]=0,b[0]=1;
    cin>>n;
    for(i=1;i<=n;i++)
        cin>>t,a[i]=a[i-1]^t,b[a[i]]++;

    cin>>q;
    while(q--)
    {  
        int sum=0,s;
        cin>>s;
        for(i=0;i<=n;i++)
            sum+=b[a[i]^s];
        cout<<sum*0.5<<endl;

    }

}

最后这里解释下b【0】=1的原因,如果 s=b【i】,那么异或值为0,也就是b【0】。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我不会c语言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值