计蒜客MORE XOR

Given a sequence of n n n numbers a 1 a_1 a1, a 2 a_2 a2, ⋯ \cdots , a n a_n an and three functions.

Define a function f(l,r)f(l,r) which returns ⊕ \oplus a[x] (l ≤ \le x ≤ \le 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).

Define a function w(l,r)w(l,r) which returns ⊕ \oplus g(x,y)(l ≤ \le x ≤ \le y ≤ \le r).

You are also given a number of xor-queries. A xor-query is a pair (i, j) (1 ≤ \le i ≤ \le j ≤ \le ). For each xor-query (i, j), you have to answer the result of function w(l,r).

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

For each test case:

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

Line 2: n numbers a 1 a_1 a1, a 2 a_2 a2, ⋯ \cdots , a n a_n an (1 ≤ \le a i a_i ai ≤ \le 10^9).

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

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

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

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

题意

求W(l,r)
W(l,r) = 所有的g(x,y) { (x,y)| x,y ∈ (l, l+1, l+2, …, r) } 的异或
g(l,r) = 所有的 f(x,y) { (x,y)| x,y ∈ (l, l+1, l+2, …, r) } 的异或
f(l,r) = 所有的 X i X_i Xi { i | i ∈ (l, l+1, l+2, …, r) } 的异或

分析

求异或,先看一下异或的性质吧 >> https://blog.csdn.net/codertcm/article/details/89440590
先简化一下g函数:

通过写了几组样例,发现g(l,r) 的值 与 X l X_l Xl … \dots X r X_r Xr 以及 len=r-l+1 有关。
X l X_l Xl … \dots X r X_r Xr 从原数组抽出来找规律,即将 X l X_l Xl … \dots X r X_r Xr 转化为 t 1 t_1 t1 … \dots t l e n t_{len} tlen
通过列举情况:
得到一张表F1:

len 系数
1 1
2 2 2
3 3 4 3
4 4 6 6 4

其中第n行是由下面的三角形进行前缀和运算得到
1
1 2
1 2 3
1 2 3 4

表F1能干什么:
对与一个g(l ,r) , 若len = r - l + 1 = 2; 则有g(l, r) = 2 个 X l X_l Xl 和 2 个 X r X_r Xr 的异或
同理, len = r - l + 1 = 3; 则有g(l, r) = 3 个 X l X_l Xl 和 6 个 X l + 1 X_{l+1} Xl+1 以及 3 个 X r X_r Xr 的异或

简化一下w函数

在定义一个c[i][j], i 代表所求区间长度为i, j 代表第j项的系数
经枚举样例
有 c[i][j] = ( i + j ) j 2 \frac{ (i+j)j }{2} 2(i+j)j ∗ \ast ( 1 + i − j + 1 ) ( i − j + 1 ) 2 \frac{ (1+i-j+1)(i-j+1) }{2} 2(1+ij+1)(ij+1)
于是对W(l , r), 当 len=r-l+1 有 W(l , r) = c[2][1] 个 X l X_l Xl 和 c[2][2] 个 X r X_r Xr 的异或

打表找规律
len 系数
1 1
2 3 3
3 6 9 6
4 10 18 18 10

利用 a ^ a = 0, a ^ 0 = a;
只需找出系数为奇数的数,再进行一次异或就行。

len 奇偶性
1 1
2 1 1
3 0 1 0
4 0 0 0 0
5 1 0 0 0 1
6 1 1 0 0 1 1
7 0 1 0 0 0 1 0
8 0 0 0 0 0 0 0 0
9 0 1 0 0 0 1 0 0 1
10 1 1 0 0 1 1 0 0 1 1

仔细观察,
将系数序列每4个分成一段,有:

  • len % 4 == 0
    所有数都不进行异或
  • len % 4 == 1
    每段的第一个进行异或
  • len % 4 == 2
    每段的第一二个进行异或
  • len % 4 == 3
    每段的第二个进行异或

终于将规律找出来了,可这样写会超时,还要用一下前缀和。前缀和也要修改一下。
计蒜客MORE XOR_第1张图片

代码

#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long int LL;
const int N = 100100;
LL a[N];
LL sum[N];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        LL n;
        scanf("%lld",&n);
        memset(sum,0,sizeof(sum));
        for(LL i=1; i<=n; i++)
        {
            scanf("%lld",&a[i]);
            if(i <= 4)
                sum[i] = a[i];
            else
                sum[i] = sum[i-4] ^ a[i];
        }
        LL l,r;
        LL q;
        scanf("%lld",&q);
        while(q--)
        {
            scanf("%lld%lld",&l,&r);
            LL len = r - l + 1;
            LL ans = 0;
            if(len % 4 == 1)
            {
                if(len == 1)
                    ans = a[l];
                else
                    ans = sum[r] ^ sum[ ((l-4<0) ? 0 : (l-4)) ];
            }
            else if(len % 4 == 2)
            {
                if(len == 2)
                    ans = a[r] ^ a[l];
                else
                    ans = sum[r] ^ sum[r - 1] ^ sum[ ((l-4<0) ? 0 : l-4) ] ^ sum[ ((l-4+1<0) ? 0 : l-4+1) ];
            }
            else if(len % 4 == 3)
            {
                if(len == 3)
                    ans = a[l+1];
                else
                    ans = sum[r - 1] ^ sum[ ((l-4+1<0) ? 0 : l-4+1) ];
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

总结

超时可以用前缀和优化
前缀和别求错了

你可能感兴趣的:(数学)