6759: 异或序列

 

6759: 异或序列

时间限制: 1 Sec  内存限制: 128 MB
题目描述
已知一个长度为n的整数数列a1,a2,…,an,给定查询参数l、r,问在a l,a l+1,…,a r区间内,有多少子序列满足异或和等于k。也就是说,对于所有的x,y(l≤x≤y≤r),满足a x⊕a x+1⊕⋯⊕a y=k的x,y有多少组。

 

输入
输入第一行为3个整数n,m,k。第二行为空格分开的n个整数,即a 1,a 2,…,an。接下来m行,每行两个整数l j,r j,代表一次查询。

 

输出
输出共m行,对应每个查询的计算结果。

 

样例输入
4 5 1
1 2 3 1
1 4
1 3
2 3
2 4
4 4

 

样例输出
4
2
1
2
1

 

提示

对于30%的数据,1≤n,m≤1000。
对于100%的数据,1≤n,m≤105,0≤k,ai≤105,1≤lj≤rj≤n。

 

来源/分类

重庆OI2018 

 

看到多次区间查询,就想到了莫队算法,但是莫队中对于区间状态转移的处理却是需要斟酌。

题目已经很明显的提示了,异或异或,也许我们应该使用异或前缀和,(orz)

对于异或前缀和 我们知道 i and j 之间的异或和 == sum[j]^sum[i-1] 

那么对于l 如果小于 Q.l-1,那么我们就先清除这位置的影响,然后下标++

如果大于Q.l-1,那就下标--,再加上这位置影响

我们要让求异或为k的组合数

sum[j] ^ sum[i] = k 即 sum[j] ^ k = sum[i]

用cnt 记录 区间内前缀和的数量变化

那么ans += val * (cnt[sum[j] ^ k])即这个点所造成的k组数影响

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<math.h>
 4 #include<algorithm>
 5 using namespace std;
 6  
 7 const int maxn = 1e5+5;
 8 int n,m,k;
 9 int block;
10 int sum[maxn];
11 int ans;
12 int tmp;
13 int cnt[maxn];
14  
15 struct node
16 {
17     int l,r,id,ans;
18     friend bool operator < (const node &a,const node&b)
19     {
20         if(a.l / block != b.l / block)return a.l < b.l;
21         return a.r < b.r;
22     }
23     node(){}
24     node(int l,int r,int id):l(l),r(r),id(id){}
25 }Q[maxn];
26  
27 bool cmp(node a,node b)
28 {
29     return a.id < b.id;
30 }
31  
32 void revise(int x,int val)
33 {
34     cnt[sum[x]]+=val;
35     ans += val*cnt[sum[x]^k];
36 }
37 int main()
38 {
39     scanf("%d%d%d",&n,&m,&k);
40     block = sqrt(n);
41     for(int i=1;i<=n;i++)
42     {
43         scanf("%d",&tmp);
44         sum[i] = tmp ^ sum[i-1];
45     }
46     for(int i=1;i<=m;i++)
47     {
48         scanf("%d%d",&Q[i].l,&Q[i].r);
49         Q[i].id = i;
50     }
51     sort(Q+1,Q+m+1);
52     int l = 1,r = 0;
53     ans = 0;
54     for(int i=1;i<=m;i++)
55     {
56         while(l < Q[i].l - 1)revise(l,-1),l++;
57         while(l > Q[i].l - 1) l--,revise(l,1);
58         while(r < Q[i].r)r++,revise(r,1);
59         while(r > Q[i].r)revise(r,-1),r--;
60         Q[i].ans = ans;
61     }
62     sort(Q+1,Q+m+1,cmp);
63     for(int i=1;i<=m;i++)printf("%d\n",Q[i].ans);
64     return 0;
65 }
View Code

 

转载于:https://www.cnblogs.com/iwannabe/p/9539460.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值