【题解】CSP-J模考-2-失误

题面


前置知识

位运算,前缀异或和。

位运算

要解决这道题,我们只用了解一种:按位异或运算。
什么是按位异或呢?

异或:只有两个值不同时才为 1,其余状态为0。
要求按位异或时可以使用转二进制+竖式的方法.
例:求711的按位异或。
第一步:转二进制
7_{10}=111_2
11_{10}=1011_2
第二步:竖式计算

1011
0111
----
1100

第三步:转十进制
1100_2=12_{10}
所以7按位异或11为12。

异或有三大运算律,分别是:

  1. 交换律a⊕b=b⊕a
  2. 结合律(a⊕b)⊕c=a⊕(b⊕c)
  3. 自反律a⊕b⊕a=b

异或在C++中为^


前缀异或和

假设我们的数组为 a_1a_n
现在我们新建一个数组 s
定义 s_ia_1 \oplus a_2\,\oplus\,...\oplus\,a_i
此时的我们会发现一个很有趣的性质。
s_r\oplus s_{l-1}=a_l \oplus a_{l+1}\,\oplus\,...\oplus\,a_r
Why?
因为异或有自反律
我们以 r=4,l=5 的情况举例:
s_5=a_1 \oplus a_2\,\oplus\,...\oplus\,a_5
s_{4-1}=a_1 \oplus a_2\,\oplus\,a_3
s_5\oplus s_3抵消 a_1 \oplus a_2\,\oplus\,a_3
就能得到 s_5\oplus s_3=a_4\oplus a_5


思路梳理

先做一遍前缀异或和
再枚举 1n-1打擂台求出最大最小值。
每次结果=(s_i+a_{i+1})\oplus s_n\oplus s_i+1


代码实现

核心代码:

for(long long i=1;i<n;i++){
	maxx=max(maxx,(s[i]+a[i+1])^(s[n]^s[i+1]));
	minn=min(minn,(s[i]+a[i+1])^(s[n]^s[i+1]));
}
4 个赞

还可以用一个后缀异或数组,这样就不需要了解自反性了

确实,你这种做法适合像我这样的萌新。

1 个赞

求个赞,谢谢。

1 个赞

你这个做法太复杂了,一个异或前缀和不就搞定了吗?
不过能想出这种方法本蒟蒻表示%%%;

1 个赞

我用的就是异或前缀和啊。