前置
没打这场。补题的时候被这题卡了会儿,由于我本身对二进制运算(尤其是异或)不熟悉,所以写这篇题解,以加深自己对异或的理解。
题意简述
共 t t t 组测试数据。
给定一个整数 n n n ,一个长度为 n n n 的数组 a a a ,和一个长度为 n n n 的01字符串。
你需要处理 q q q 个询问。对于每个询问,先给定一个整数 o p op op ,表示操作类型。
o
p
=
1
op=1
op=1 时,给定两个整数
l
,
r
l,r
l,r ,翻转
s
l
,
.
.
.
,
s
r
s_l,...,s_r
sl,...,sr (即, 0
变为 1
, 1
变为 0
)。
o p = 2 op=2 op=2 时,给定一个整数 x x x ( x x x 为0或1)。求出所有满足 s i = x s_i=x si=x 的 a i a_i ai 全部异或起来的结果。
比如对于下面这组输入:
1 //t
5 //n
2 4 6 8 10 //a数组
00101 //字符串s
1 //q
2 1 //op&x
应该输出 a 3 ⊕ a 5 a_3 \oplus a_5 a3⊕a5 (即 6 ⊕ 10 6 \oplus 10 6⊕10 )的结果。
解题思路
首先有如下两个异或的基本式子:
x ⊕ x = 0 x \oplus x=0 x⊕x=0
0 ⊕ x = x 0 \oplus x=x 0⊕x=x
有了这两个式子,就能解决这题了。
记 a n s 0 ans0 ans0 为输入的 o p = 2 op=2 op=2 且 x = 0 x=0 x=0 时应输出的结果, a n s 1 ans1 ans1 为输入的 o p = 2 op=2 op=2 且 x = 1 x=1 x=1 时应输出的结果。
我们来考虑怎么处理操作 1 1 1 (以下面这组数据为例)。
1 //t
6 //n
2 4 6 8 10 12 //a数组
001011 //字符串s
2 //q
1 2 5 //op&x
2 1
初始时,
a
n
s
1
=
a
3
⊕
a
5
⊕
a
6
ans1=a_3 \oplus a_5 \oplus a_6
ans1=a3⊕a5⊕a6 。进行完操作
1
1
1 后,字符串被反转成了 010101
。此时的
a
n
s
1
=
a
2
⊕
a
4
⊕
a
6
ans1=a_2 \oplus a_4 \oplus a_6
ans1=a2⊕a4⊕a6 。最关键的是:
( a 3 ⊕ a 5 ⊕ a 6 ) ⊕ ( a 2 ⊕ a 3 ⊕ a 4 ⊕ a 5 ) = a 2 ⊕ a 4 ⊕ a 6 ⊕ ( a 3 ⊕ a 3 ) ⊕ ( a 5 ⊕ a 5 ) = a 2 ⊕ a 4 ⊕ a 6 (a_3 \oplus a_5 \oplus a_6) \oplus (a_2 \oplus a_3 \oplus a_4 \oplus a_5)=a_2 \oplus a_4 \oplus a_6 \oplus (a_3 \oplus a_3) \oplus (a_5 \oplus a_5)=a_2 \oplus a_4 \oplus a_6 (a3⊕a5⊕a6)⊕(a2⊕a3⊕a4⊕a5)=a2⊕a4⊕a6⊕(a3⊕a3)⊕(a5⊕a5)=a2⊕a4⊕a6 !
以及:
a 2 ⊕ a 3 ⊕ a 4 ⊕ a 5 = ( a 1 ⊕ a 1 ) ⊕ ( a 2 ⊕ a 3 ⊕ a 4 ⊕ a 5 ) = a 1 ⊕ ( a 1 ⊕ a 2 ⊕ a 3 ⊕ a 4 ⊕ a 5 ) a_2 \oplus a_3 \oplus a_4 \oplus a_5=(a_1 \oplus a_1) \oplus (a_2 \oplus a_3 \oplus a_4 \oplus a_5)=a_1 \oplus (a_1 \oplus a_2 \oplus a_3 \oplus a_4 \oplus a_5) a2⊕a3⊕a4⊕a5=(a1⊕a1)⊕(a2⊕a3⊕a4⊕a5)=a1⊕(a1⊕a2⊕a3⊕a4⊕a5) !
于是只需要开个数组 p p p , p i = a 1 ⊕ a 2 ⊕ … ⊕ a i p_i=a_1 \oplus a_2 \oplus … \oplus a_i pi=a1⊕a2⊕…⊕ai ,就可以解决本题了(具体细节见代码)。
代码示例
#include<bits/stdc++.h>
using namespace std;
int t,n,a[200010],p[200010];
string s;
signed main(){
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
cin>>s;
s=" "+s;
int sum1=0,sum2=0;//即上文ans1,ans0
p[0]=0;
for(int i=1;i<=n;i++){
p[i]=p[i-1]^a[i];
if(s[i]=='1') sum1^=a[i];
else sum2^=a[i];
}
int q;
cin>>q;
while(q--){
int op,x,l,r;
cin>>op;
if(op==1){
cin>>l>>r;
sum1^=p[l-1]^p[r];
sum2^=p[l-1]^p[r];
}else{
cin>>x;
if(x==0) cout<<sum2<<" ";
else cout<<sum1<<" ";
}
}
cout<<endl;
}
return 0;
}