有趣的区间异或值
时间限制(普通/Java) :
2000 MS/ 6000 MS 运行内存限制 : 65536 KByte
总提交 : 354 测试通过 : 35
题意:中文题不解释
总提交 : 354 测试通过 : 35
比赛描述
按照下列规则生成一个序列,当x > 0时 A[x] = A[x-1] xor x,当x == 0时,即A[0] = 0,当然,题目没有这么简单,有n组查询,对于每组询问L,R,就要输出序列A[L] xor A[L+1] xor A[L+2]...xor A[R-1] xor A[R],即这个序列下标在[L,R]区间内的异或值。
输入
第一行一个数字N,表示N组询问(N <= 105),接下来N行,第i行给出第i组询问的L,R(1<=L<=R<=109)
输出
输出N行,每行一个数,即序列下标在[L,R]区间内的异或值
样例输入
4
1 5
2 8
3 10
10 100
样例输出
7
9
0
111
思路:直观看这道题没什么思路,想到是异或可能有规律,于是打表找规律之。
果然,Ai是每隔4个出现一个0,前缀和是每隔8个出现一个0
那么4和8就分别是这两个的循环节了,处理一下就好
对于l~r这个区间我们可以简单化,结果为xo(r)-xo(l-1),利用了0~l-1这段区间异或两次变成0的性质
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
void init()
{
int n=0,sum=0;
for(int i=1; i<=100; i++)
{
printf("%d %d\n",n,sum);
n^=i;
sum^=n;
}
}
long long xo(int x)///A0xorA1...xorAx
{
long long n=0,sum=0;
if(x<=7)
for(int i=1; i<=x; i++)
{
n^=i;
sum^=n;
}
else
{
int m=x;
m-=7;
int pos=m%8;
if(x<4)
for(int i=1; i<=x; i++)
n^=i;
m-=3;
int pos1=n%4;
for(int i=x-pos1+1; i<=x; i++)
n^=i;
for(int i=x-pos+1; i<=x; i++)
{
n^=i;
sum^=n;
}
}
return sum;
}
int main()
{
int T,l,r;
//init();
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&l,&r);
printf("%lld\n",xo(r)^xo(l-1));
}
return 0;
}