Description
在 LJJ 的“压迫”下,每一个蒟蒻要出三道题,正所谓哪里有剥削哪里就有反抗,蒟蒻们给强大的 LJJ 出了一道题,若是 LJJ 解出了题,蒟蒻们才心甘情愿给 LJJ 当苦力。问题其实很简单:给你一个区间 L 到 R,要求你求出从 L 异或到 R 的值。可是LJJ还(不)有(屑)很(作)多(这)事(种)要(水)忙(题),因而他找到了你但愿你能写个程序帮他解决这道题。html
Input
第一行一个T(1 ≤ L ≤ T ≤ 1e5),表示有 T 组输入。算法
如下 T 行,每行包含两个整数 L 和 R(1 ≤ L ≤ R ≤ 1e5)用空格分开,表示要求异或和的区间。数组
Output
对于每组输入,输出一个整数表示 L 到 R 全部数字的异或和markdown
Sample Input
2
1 2
3 6
Sample Output
3
4
Hint
异或(xor)是一个数学运算符。它应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“xor”。网络
0 ⊕ 0 = 0,1 ⊕ 0 = 1, 0 ⊕ 1 = 1, 1 ⊕ 1 = 0。ide
性质:a ⊕ a = 0, a ⊕ 0 = aatom
C语言中能够用“^”进行异或运算。spa
样例1: 1 ⊕ 2 = 3,样例 2:3 ⊕ 4 ⊕ 5 ⊕ 6 = 4设计
#include <cstdio> const int maxn = 1e5 + 10; int xorSum[maxn], t, l, r; int main() { xorSum[1] = 1; for(int i = 2;i < maxn;++i) { xorSum[i] = i ^ xorSum[i - 1]; } scanf("%d", &t); while(t--) { scanf("%d %d", &l, &r); printf("%d\n", xorSum[r] ^ xorSum[l - 1]); } return 0; }
这题暴力算法确定是 O ( n t ) O(nt) O(nt),确定是没法经过的!code
这种区间和查询的问题,最简单的思路就是前缀和、差分,其次就是线段树之类的。先看看前缀和,这里的前缀和显然和通常的前缀和不同,普通的前缀和是设定数组 S u m [ i ] = a [ i ] + S u m [ i − 1 ] Sum[i] = a[i] + Sum[i-1] Sum[i]=a[i]+Sum[i−1],用加法来描述一种“和”,而这里不是求和,而是求区间的异或。那么异或和求和有什么共同点呢?
求和是前缀的累积再加上当前值,而异或也是前缀的异或累计再异或当前值,这本质上是同样的!
那么有什么区别呢?
在对前缀和进行差分的时候,是直接相减,那是由于:
S u m ( l , r ) = a [ l ] + … + a [ r ] = S u m [ r ] − S u m [ l − 1 ] Sum(l, r) = a[l]+…+a[r]=Sum[r]-Sum[l-1] Sum(l,r)=a[l]+…+a[r]=Sum[r]−Sum[l−1]
而对前缀异或进行差分的时候,是怎样的呢?先推导一下:
x o r S u m ( l , r ) = ( a [ 1 ] ⊕ … ⊕ a [ r ] ) ⊕ ( a [ 1 ] ⊕ … a [ l − 1 ] ) xorSum(l, r)=(a[1]⊕…⊕a[r])⊕(a[1]⊕…a[l-1]) xorSum(l,r)=(a[1]⊕…⊕a[r])⊕(a[1]⊕…a[l−1])
这是由于: ( a ⊕ b ) ⊕ b = a (a⊕b)⊕b=a (a⊕b)⊕b=a,因此差分能够归结为:
x o r S u m ( l , r ) = x o r S u m [ r ] ⊕ x o r S u m [ l − 1 ] xorSum(l, r)=xorSum[r]⊕xorSum[l-1] xorSum(l,r)=xorSum[r]⊕xorSum[l−1]
综上所述,程序就很好编写了!
有想要探讨、合做的小伙伴能够关注我,有问题能够发邮件给我,个人邮箱是:2329313458@qq.com