MORE XOR (区间多次异或求值,规律)

Given a sequence of nn numbers a_1, a_2, \cdots, a_na1​,a2​,⋯,an​ and three functions.

Define a function f(l,r)f(l,r) which returns \oplus a[x]⊕a[x] (l \le x \le rl≤x≤r). The \oplus⊕ represents exclusive OR.

Define a function g(l,r)g(l,r) which returns \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) which returns \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,j) (1 \le i \le j \le n1≤i≤j≤n). For each xor-query (i, j)(i,j), you have to answer the result of function w(l,r)w(l,r).

Input

Line 11: t (1 \le t \le 20)t(1≤t≤20).

For each test case:

Line 11: n (1 \le n \le 100000)n(1≤n≤100000).

Line 22: nn numbers a_1, a_2, \cdots, a_n (1 \le a_i \le 10^9)a1​,a2​,⋯,an​(1≤ai​≤109).

Line 33: q (1 \le q \le 100000)q(1≤q≤100000), the number of xor-queries.

In the next qq lines, each line contains 22numbers i, ji,j representing a xor-query (1 \le i \le j \le n)(1≤i≤j≤n).

It is guaranteed that sum of nn and q \le 10^6q≤106.

Output

For each xor-query (i, j)(i,j), print the result of function 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

2019武昌赛区网络赛

题意:T组数据,每组数据先输入一个n , 然后n个数,q次查询,输出 w ( l , r );

         规则:f( l , r ) = l ^ ( l + 1) ^ ( l + 2 ) ^ ... ^  r 

                   g( l , r ) =  f( x1 ,y1 ) ^ f(x2,y2) ^....          ( l <= xi , yi <= r )

                   w( l , r ) =  g( x1 ,y1 ) ^ g(x2,y2) ^....          ( l <= xi , yi <= r )

思路:先暴力打表观察规律,

得出的结论是:从x开始,每四个点特性循环一次。

         特性:假设有一些点 : a , b , c , d ,  e , f , g , h , i , j , k 

        1 - > 1:  a                                               

        1 - > 2:  a ^ b                                              2 - > 2: b

        1 - > 3:  b                                                    2 - > 3: b ^ c

        1 - > 4:  0                                                    2 - > 4: c

 

        1 - > 5:  a ^ e                                              2 - > 5: 0

        1 - > 6:  a ^ b ^ e ^ f                                    2 - > 6: b ^ f

        1 - > 7:  b ^ f                                                2 - > 7: b ^ c ^ f ^ g

        1 - > 8:  0 ^ 0                                               2 - > 8: c ^ g

也就是说,每4个一循环的特性不随起点而改变,只是在对应区间异或特性对应的值。

那么我们再来看:

         5 - > 5 :e

         5 - > 6 :e ^ f

         5 - > 7: f

         5 - > 8:0

也就是说:以5为开头的其实是可以通过以1为开头的找到的,同理以6开头可以在以2开头的里面找到,以7开头可以在以3开头的里面找到,以8开头可以在以4开头的里面找到.......

所以说我们只需要打一个 以 i 为开头,到达任意点的s的表就好了,我在这里假设为a[ i ][ j ] : 代表 以 i 开头,到达 j 点的值。

 

代码如下:

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
#define N 100010
using namespace std;
const double pi=acos(-1.0);
int a[N];
int v[5][N];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        memset(v,0,sizeof(v));
        memset(a,0,sizeof(a));
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        for(int i=1; i<=4; i++)  //以 i 开头
        {
            //4个一循环的 循环特性
            for(int j=i; j<=n; j+=4)  //第一个异或自己
            {
                if(j-4>=i)      
                    v[i][j]=v[i][j-4]^a[j];
                else
                    v[i][j]=a[j];
            }
            for(int j=i+1; j<=n; j+=4) //第二个 异或前两个值
            {
                if(j-4>=i)
                    v[i][j]=v[i][j-4]^a[j]^a[j-1];
                else
                    v[i][j]=a[j]^a[j-1];
            }
            for(int j=i+2; j<=n; j+=4)  //第三个 异或第二个值
            {
                if(j-4>=i)
                    v[i][j]=v[i][j-4]^a[j-1];
                else
                    v[i][j]=a[j-1];
            }                          //第四个是 0,省略
        }
        int m;
        scanf("%d",&m);
        while(m--)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            if((r-l+1)%4==0)      //区间长度为4的倍数,直接为0
                printf("0\n");
            else
            {
                if(l>4)           //开头大于4,需要在[1,4]开头里面找
                {
                    int p=l%4;    //在以p开头里面找
                    if(p==0)p=4;
                    
                    int x=l-4+(r-l)%4; //要把上一个 循环中的值给异或掉,x 为上一个循环中的哪一个
                    printf("%d\n",v[p][x]^v[p][r]);
                }
                else printf("%d\n",v[l][r]);
            }
        }
    }
    return 0;
}
/*
100
10
1 2 3 4 5 6 7 8 9 10
100
*/

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值