CF1872E Data Structures Fan 题解

前置

没打这场。补题的时候被这题卡了会儿,由于我本身对二进制运算(尤其是异或)不熟悉,所以写这篇题解,以加深自己对异或的理解。

题意简述

t t t 组测试数据。

给定一个整数 n n n ,一个长度为 n n n 的数组 a a a ,和一个长度为 n n n01字符串

你需要处理 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变为 11变为 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 a3a5 (即 6 ⊕ 10 6 \oplus 10 610 )的结果。

解题思路

首先有如下两个异或的基本式子:

x ⊕ x = 0 x \oplus x=0 xx=0

0 ⊕ x = x 0 \oplus x=x 0x=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=a3a5a6 。进行完操作 1 1 1 后,字符串被反转成了 010101。此时的 a n s 1 = a 2 ⊕ a 4 ⊕ a 6 ans1=a_2 \oplus a_4 \oplus a_6 ans1=a2a4a6 。最关键的是:

( 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 (a3a5a6)(a2a3a4a5)=a2a4a6(a3a3)(a5a5)=a2a4a6

以及:

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) a2a3a4a5=(a1a1)(a2a3a4a5)=a1(a1a2a3a4a5)

于是只需要开个数组 p p p p i = a 1 ⊕ a 2 ⊕ … ⊕ a i p_i=a_1 \oplus a_2 \oplus … \oplus a_i pi=a1a2ai ,就可以解决本题了(具体细节见代码)。

代码示例

#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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值