基本信息
文件名称:56、简单的异或难题.docx
文件大小:19.17 KB
总页数:3 页
更新时间:2025-02-08
总字数:约1.24千字
文档摘要

解题思路

首先我们要知道异或运算的两个特性:

如果有两个相同的数进行异或运算,那么运算的结果为?0?,比如?2⊕2=0。

一个数和0?进行异或运算,该数不变,比如2⊕0=2?。

题目让我们求得是区间?[l,r]?中出现次数为奇数的数的异或和,那么我们就要去掉那些出现次数为偶数的数再进行异或运算。

但实际上,因为那些数的出现次数是偶数,所以我们对它们进行异或和运算后,结果为0。所以这些出现次数为偶数的数,即便我们再进行异或和运算的时候把它们也进行了运算,也不会影响我们的结果的。

换句话来说,就是我们直接计算第?l?个数到第?r?个数的异或和就行。不需要处理那些出现次数为偶数的数。

现在问题就是如何快速的求出第?l?个数到第?r?个数的异或和。

这里还是要用到上面的第一个性质,比如我们要计算?33?到?55?的异或和:

一段?11?到?55?的异或和运算为:1⊕2⊕3⊕4⊕5。

一段?11?到?22?的异或和运算为:?1⊕2。

两段进行异或和运算,我们可以知道,11?和?22?都进行了两次异或,所以它们就不会影响结果了,此时,我们就得到了3⊕4⊕5?,即?3?到?5?的异或和。

大家可以发现,这和我们的前缀和思想非常相似,我们可以称之为前缀异或。

用?11?个数组?ss?来预处理前缀异或:s[i]?表示第?11?个数到第?i个数的前缀异或和。

对于每次询问[l,r]?,我们只需计算s[r]⊕s[l?1]?即可。

一共有m?次询问,处理每次询问的复杂度为?O(1)?。

注意,因为本题输入输出数据较大,所以要用快一些的输入输出方式,比如?scanf?和?printf?。如果想使用cin?和cout?,需要关闭流同步。

以及换行不能使用?endl?作为换行符,要用??n?。

时间复杂度:O(m)?。

AC_Code

C++

#includeiostream

usingnamespacestd;

#includevector

#includealgorithm

constintN=1e5+50;

inta[N],s[N];

intmain()

{

ios_base::sync_with_stdio(false);

cin.tie(nullptr);

cout.tie(nullptr);

intn,m,l,r;

cinnm;

for(inti=1;i=n;i++)

{

cina[i];

s[i]=s[i-1]^a[i];

}

while(m--)

{

cinlr;

cout(s[r]^s[l-1])endl;

}

return0;

}