[ABC274Ex] XOR Sum of Arrays

section>

Problem Statement

For sequences B=(B1,B2,,BM) and C=(C1,C2,,CM), each of length M, consisting of non-negative integers, let the XOR sum S(B,C) of B and C be defined as the sequence (B1C1,B2C2,...,BMCM) of length M consisting of non-negative integers. Here, represents bitwise XOR.
For instance, if B=(1,2,3) and C=(3,5,7), we have S(B,C)=(13,25,37)=(2,7,4).

You are given a sequence A=(A1,A2,,AN) of non-negative integers. Let A(i,j) denote the contiguous subsequence composed of the i-th through j-th elements of A.
You will be given Q queries explained below and asked to process all of them.

Each query gives you integers a, b, c, d, e, and f, each between 1 and N, inclusive. These integers satisfy ab, cd, ef, and ba=dc. If S(A(a,b),A(c,d)) is strictly lexicographically smaller than A(e,f), print Yes; otherwise, print No.

What is bitwise XOR? The exclusive logical sum ab of two integers a and b is defined as follows.
  • The 2k's place (k0) in the binary notation of ab is 1 if exactly one of the 2k's places in the binary notation of a and b is 1; otherwise, it is 0.
For example, 35=6 (In binary notation: 011101=110).
What is lexicographical order on sequences?

A sequence A=(A1,,A|A|) is said to be strictly lexicographically smaller than a sequence B=(B1,,B|B|) if and only if 1. or 2. below is satisfied.

  1. |A|<|B| and (A1,,A|A|)=(B1,,B|A|).
  2. There is an integer 1imin{|A|,|B|} that satisfies both of the following.
    • (A1,,Ai1)=(B1,,Bi1).
    • Ai<Bi.

Constraints

  • 1N5×105
  • 0Ai1018
  • 1Q5×104
  • 1abN
  • 1cdN
  • 1efN
  • ba=dc
  • All values in the input are integers.

Input

The input is given from Standard Input in the following format, where queryi represents the i-th query:

$N$ $Q$
$A_1$ $A_2$ $\dots$ $A_N$
$\text{query}_1$
$\text{query}_2$
$\vdots$
$\text{query}_Q$

The queries are in the following format:

$a$ $b$ $c$ $d$ $e$ $f$

Output

Print Q lines. The i-th line should contain the answer to the i-th query.


Sample Input 1

4 5
1 2 3 1
1 3 2 4 1 4
1 2 2 3 3 4
1 1 2 2 3 4
1 2 2 3 3 3
1 4 1 4 1 1

Sample Output 1

No
No
Yes
No
Yes

For the first query, we have A(1,3)=(1,2,3) and A(2,4)=(2,3,1), so S(A(1,3),A(2,4))=(12,23,31)=(3,1,2). This is lexicographcially larger than A(1,4)=(1,2,3,1), so the answer is No.
For the second query, we have S(A(1,2),A(2,3))=(3,1) and A(3,4)=(3,1), which are equal, so the answer is No.


Sample Input 2

10 10
725560240 9175925348 9627229768 7408031479 623321125 4845892509 8712345300 1026746010 4844359340 2169008582
5 6 5 6 2 6
5 6 1 2 1 1
3 8 3 8 1 6
5 10 1 6 1 7
3 4 1 2 5 5
7 10 4 7 2 3
3 6 1 4 7 9
4 5 3 4 8 9
2 6 1 5 5 8
4 8 1 5 1 9

Sample Output 2

Yes
Yes
Yes
Yes
No
No
No
No
No
No

很明显,是哈希的题。要判断哪个字典序大,可以通过二分找到第一个 i 使 aibi 然后判断 aibi 的大小。然后二分过程中只需要判断两个序列是否相同,就可以用哈希判断。

官方题解的做法太神奇,这里参考了大多赛时AC程序的方法。

首先如果把异或改成加法,就是使用经典的 Robin-Karp 哈希。以一个数 x 作为位权,定义一个序列 a1,a2ak 的哈希值为 xk1a1+xk2a2xak1+ak 这个 x 可以随机取。然后易得序列 a1+b1,a2+b2ak+bk 的哈希值就是 a 序列的哈希值加上 b 序列的哈希值。所以判断是否是否相同就可以直接将前两个的哈希值相加判断是否与第三个序列相同。

但是异或呢?如果是异或的话,我们的哈希就完全不行了,因为乘法对异或没有分配律。我们要找一种运算对异或满足分配律的,想到与和或,但是他们都不支持幂次。

这个运算是矩阵乘法。不妨把一个二进制当作一个行向量。众所周知,正常矩阵乘法的形式是 ci,j=ai,j×bj,k

然后把他修改成 ci,j=ai,jbj,k
仍然表示异或, 表示按位与。

根据矩阵的结论,由于按位与对异或有分配律,所以其实这样出来的矩阵具有结合律,对异或具有分配律。所以方法就是以一个随机01矩阵为位权。这样哈希时我们就可以直接将两个序列的哈希值异或起来,是与按位异或后的序列的哈希值相等。

但是这样一次矩阵乘法的复杂度是 log3,算上二分过不了?类似的以位运算为运算的矩阵乘法大多是可以压位的。观察上面的式子,如果 ai,j=1,ci=bj(c,b已经压成了二进制)。矩阵乘法复杂度降到 log2

另外,由于矩阵满足分配律,所以可以预处理矩阵的幂后,可以像正常的哈希一样直接提取出区间 [l,r] 的哈希值。但是我保险起见,打了一个倍增。这样更有可能对。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL; 
const int N=5e5+5,M=63;
mt19937_64 gen(time(0));
struct matrix{
	int a[M];
	void init()
	{
		for(int i=0;i<M;i++)
			a[i]=1LL<<i;
	}
	matrix operator*(const matrix&b)const{
		matrix c;
		memset(c.a,0,sizeof(c.a));
		for(int i=0;i<M;i++)
			for(int j=0;j<M;j++)
				if(a[i]>>j&1)
					c.a[i]^=b.a[j];
		return c;
	}
	void operator=(matrix b){
		for(int i=0;i<M;i++)
			a[i]=b.a[i];
	}
}pw[25]; 
LL mul(LL x,matrix a)
{
	LL ret=0;
	for(int i=0;i<M;i++)
		if(x>>i&1)
			ret^=a.a[i];
	return ret;
}
LL x[N],st[25][N];
int n,q,a,b,c,d,e,f;
int main()
{
	scanf("%d%d",&n,&q);
	for(int i=0;i<M;i++)
		pw[0].a[i]=gen();
	for(int i=1;i<=n;i++)
		scanf("%lld",x+i),st[0][i]=x[i];
	for(int i=1;i<25;i++)
		pw[i]=pw[i-1]*pw[i-1];
	for(int i=1;i<25;i++)
		for(int j=1;j+(1<<i)-1<=n;j++)
			st[i][j]=st[i-1][j]^mul(st[i-1][j+(1<<i-1)],pw[i-1]);
	while(q--)
	{
		scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f);
		int l=0;
		for(int i=24;i>=0;i--)
			if(a+l+(1<<i)<=b+1&&e+l+(1<<i)<=f+1&&(st[i][a+l]^st[i][c+l])==st[i][e+l])
				l+=1<<i;
		if(e+l>f)
			printf("No\n");
		else if(a+l>b)
			printf("Yes\n");
		else if((x[a+l]^x[c+l])<x[e+l])
			printf("Yes\n");
		else
			printf("No\n");
	}
}
posted @   灰鲭鲨  阅读(90)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示