MORE XOR
- 时间:1000ms
- 内存:262144K
Given a sequence of nnn numbers a1,a2,⋯ ,ana_1, a_2, \cdots, a_na1,a2,⋯,an and three functions.
Define a function f(l,r)f(l,r)f(l,r) which returns ⊕a[x]\oplus a[x]⊕a[x] (l≤x≤rl \le x \le rl≤x≤r). The ⊕\oplus⊕ represents exclusive OR.
Define a function g(l,r)g(l,r)g(l,r) which returns ⊕f(x,y)(l≤x≤y≤r)\oplus f(x,y)(l \le x \le y \le r)⊕f(x,y)(l≤x≤y≤r).
Define a function w(l,r)w(l,r)w(l,r) which returns ⊕g(x,y)(l≤x≤y≤r)\oplus g(x,y)(l \le x \le y \le r)⊕g(x,y)(l≤x≤y≤r).
You are also given a number of xor-queries. A xor-query is a pair (i,ji, ji,j) (1≤i≤j≤n1 \le i \le j \le n1≤i≤j≤n). For each xor-query (i,j)(i, j)(i,j), you have to answer the result of function w(l,r)w(l,r)w(l,r).
Input
Line 111: t(1≤t≤20)t (1 \le t \le 20)t(1≤t≤20).
For each test case:
Line 111: n(1≤n≤100000)n (1 \le n \le 100000)n(1≤n≤100000).
Line 222: nnn numbers a1,a2,⋯ ,an(1≤ai≤109)a_1, a_2, \cdots, a_n (1 \le a_i \le 10^9)a1,a2,⋯,an(1≤ai≤109).
Line 333: q(1≤q≤100000)q (1 \le q \le 100000)q(1≤q≤100000), the number of xor-queries.
In the next qqq lines, each line contains 222 numbers i,ji, ji,j representing a xor-query (1≤i≤j≤n)(1 \le i \le j \le n)(1≤i≤j≤n).
It is guaranteed that sum of nnn and q≤106q \le 10^6q≤106.
Output
For each xor-query (i,j)(i, j)(i,j), print the result of function w(i,j)w(i,j)w(i,j) in a single line.
样例输入
1
5
1 2 3 4 5
5
1 3
1 5
1 4
4 5
3 5
样例输出
2
4
0
1
4
题目来源:The Preliminary Contest for ICPC China Nanchang National Invitational and International Silk-Road Programming Contest
- 大意:给出n个数a[1…n],定义了三种运算
1、f(L,R)=a[L]到a[R]的异或和
2、g(L,R)=f(L,L)到f(R,R)的异或和
3、w(L,R)=g(L,L)到f(R,R)的异或和
给出多组区间,问w(L,R)的值
- 分析:可以试一些简单的数,发现g(L,R)有个很明显的规律:若L到R之间的数是奇数个,那么g(L,R)的值为L,L+2,…,R这几个位置的数的异或和;若L到R之间的数是偶数个,则g(L,R)的值为0。
因此,我们可以以w(1,5)为例,将其展开为g(L,R)的表达式,并将所需要的数的编号代入,如下表
1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|
1 | 1 | 0 | 1 3 | 0 | 1 3 5 |
2 | 2 | 0 | 2 4 | 0 | |
3 | 3 | 0 | 3 5 | ||
4 | 4 | 0 | |||
5 | 5 |
表里共有3* 1个1,2* 2个3,1* 3个5,2* 1个2,1* 2个4
假设区间L到R中有n个数,记L为第一个,L+1为第2个,以此类推。
在这n个数中,处于奇数位置的数有nj=(n/2+n%2)个,处于偶数位置的数有no=(n/2)个。
若nj为奇数,那么L,L+4,…R1(不大于R)为异或和的一部分;
若no为奇数,那么L+1,L+1+4,…R2(不大于R)为异或和的一部分;
将L到R中符合上述条件的位置的数求异或和,即为w(L,R)的值。
可通过前缀和快速计算(L,R1)(L+1,R2)的异或和。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 100005;
int a[maxn];
int sum[4][maxn];//4组前缀和
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(sum,0,sizeof(sum));
int n;
scanf("%d",&n);
for(int i = 1; i <= n; ++i)
{
scanf("%d",&a[i]);
sum[(i-1)%4][(i-1)/4+1]=sum[(i-1)%4][(i-1)/4]^a[i];
}
//输出中间变量
/*
for(int i = 0; i < 4; ++i)
{
for(int j = 0; j < 4; ++j)
printf("%d ",sum[i][j]);
printf("\n");
}*/
int q;
scanf("%d",&q);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
int nn = y-x+1; //区间大小
int no = nn/2; //偶数个数
int nj = no + nn%2;//奇数个数
int ans = 0;
if(nj&1)
{
int my = y;
while((my-1)%4!=(x-1)%4) my--;
//找到区间内x所在行的最后一个数的位置
ans^=(sum[(x-1)%4][(x-1)/4]^sum[(x-1)%4][(my-1)/4+1]);
//printf("===%d %d\n",(x-1)/4,(my-1)/4+1);
}
if(no&1)
{
x=x+1;
int my = y;
while((my-1)%4!=(x-1)%4) my--;
//找到区间内x+1所在行的最后一个数的位置
ans^=(sum[(x-1)%4][(x-1)/4]^sum[(x-1)%4][(my-1)/4+1]);
//printf("---%d %d\n",(x-1)/4,(my-1)/4+1);
}
printf("%d\n",ans);
}
}
return 0;
}