异或问题总结

刷题的时候经常遇到异或相关的题目,虽然知道是什么意思但是做题的时候总感觉力不从心,总感觉和所学的联系不上,因此总结一些我做过的或者是经典的异或问题

什么是异或?

异或简单来说就是相同的得0,相异得1,异或有一些性质例如满足交换律,结合律,自反性等等,这些性质实际上在题目中考察不多,题目更多的是考察你的思维

01的异或固然容易,但是当数据扩大到数万级别的时候就涉及到了数的拆分,把十进制转换为二进制是解决异或问题常见的一种手段,面对异或相关的问题都需要有进行位运算的思想

异或例题

1.异或和

题目意思就是给出一个区间,求区间内满足i<j的数的两两异或的和

暴力法就是枚举区间内的两个数,两两异或算出和来,当数据量较大的时候显然是不可行的

这里就需要引入一个新概念:位运算,将每一个数都转成二进制的表达形式

根据异或的性质,我们可知异或的结果只和1的个数有关,两个数之间异或,当该位上的数字异或为1,才是有贡献的,异或为0的位对我们的结果就不影响了,因此我们只需要关注1的个数即可

思路明确之后,我们的问题就改变为求区间内的数异或后各位置上的1的数量,又因为我们计算的是两两异或,因此我们要统计(0,1)数对的数量(01数对的数量也就是对答案有贡献的数据的数量)

#include<cstdio>
#include<algorithm>
using namespace std;
int ans[20]={0};//log2(100000)约为17,这里的数组大小应该开到至少20
long long int res=0;
int main()
{int n,a,i,len,mmax=-1;//mmax表示所有数中最大的二进制位数scanf("%d",&n);for(i=1;i<=n;i++){scanf("%d",&a);len=0;while(a){len++;if(a&1)ans[len]++;//记录当前位为1的个数a=a>>1;}mmax=max(mmax,len);}for(i=1;i<=mmax;i++){res+=(long long int)(1<<(i-1))*(long long int)ans[i]*(long long int)(n-ans[i]);//强转为long long}printf("%lld",res);return 0;
}
//借用一下别人的代码,看不懂的兄弟可以去看看原文       
原文链接:https://blog.csdn.net/upc122/article/details/106535437

ans统计位上1的数量后,根据排列组合公式可以得到(0,1)数对的组合数,再乘以该位的共享2^n,即可得出答案

ps:个人感觉这题是区间异或和的升级版,区间异或和比这里的更简单,统计某一个区间内的数的异或和a1^a2^a3...^an,只需要位运算加贡献思想即可

2.异或和之和

题目意思是求出l<=r的子段的异或和,再将所有的异或和进行求和

我们都懂的求区间的异或和,但是题目的子段有很多,我们枚举各子段,时间复杂度又将变成O(n2),是不满足数据要求的

很多兄弟在这里就卡住了,解决这个问题需要用到异或的一个性质:自反性 ---a^a=0,一个数和自身进行异或的结果为0,Sa-1^Sb=a~b的异或和(b>a)

那么我们就可以用前缀异或和去表示区间异或和了,我们求出前缀异或和之后就可以只用两个数就可以表示出区间异或和

巧妙的点来了,我们只需要将前缀异或和看作一个数据,那么我们就可以将本题改为求区间内任意两个数的异或的和,这样题目就变得和上一题一样了,时间复杂度也从O2降到O1

#include <bits/stdc++.h>
using namespace std;
long long n,a[100010],q[100010],w[100010][2],ans=0;
int main()
{scanf("%lld",&n);for(int i=1;i<=n;i++)scanf("%lld",&a[i]);for(int i=1;i<=n;i++)q[i]=q[i-1]^a[i];for(int i=0;i<=n;i++)for(int j=20;j>=0;j--)w[j][(q[i]>>j)&1]++;for(int i=0;i<=20;i++)ans+=w[i][0]*w[i][1]*(1<<i);printf("%lld",ans);return 0;
}

求出前缀和之后,就可以统计各位上1的个数,排列(0,1)数对,问题即可解决

关键在于将区间内的数视作一个整体

3.选数异或

题目意思是给出一个区间,问区间内是否存在两个数使得异或为x

首先想暴力法肯定是枚举区间上的两个数,一一检查他们的异或结果,时间复杂度为O2显然是不可行的,我们要想的是如何进行优化 

和上面两题不同,这里求的不是异或和,只是单纯的验证两个数的异或结果,所以上面的位运算+贡献思想是用不上的,既然无法优化成O1,我们就想如何剪枝优化,避免不必要的计算

不难想到,检查一个区间的时候只要区间内有一个异或满足条件,那么这个区间必然满足条件,因此我们可以在枚举区间之前先判断子区间是否存在异或,有则直接返回yes

#include<iostream>
using namespace std;
int main()
{int n,m,x,l,r;scanf("%d%d%d",&n,&m,&x);int e[100010];for(int i=1;i<=n;i++){scanf("%d",&e[i]);}int res[100010][2];bool exist=false;int k=0;while(m--){exist=false;scanf("%d%d",&l,&r);for(int j=1;j<=k;j++){if(l<=res[j][0]&&r>=res[j][1]){exist=true;printf("yes\n");break;}}if(exist==true)continue;for(int i=l;i<r;i++){for(int j=i+1;j<=r;j++){if((e[i]^e[j])==x){k++;res[k][0]=i;res[k][1]=j;exist=true;break;}}if(exist)break;}if(!exist)printf("no\n");else printf("yes\n");}return 0;
}

用res集去存储异或数对,每一次查询先判断区间内是否有异或数对,没有才进行枚举,这样就完成了剪枝优化

4.异或数列

题目意思是给出一组数,每次一人选择一个数,可以将自己的数或者别人的数进行异或求和,异或后数大的获胜(补充:a,b开始时都为0)

第一眼看还以为是nim,但是这里会出现平局的情况所以还是有一点不同的

涉及到求异或和,那么就需要用到位运算和贡献思想,要想异或后的数大,那么高位上的数需要为1,因为0和1异或得1,高位贡献多,因此我们抢到高位上的1即可获胜

拿到1之后需要选择让自己变还是让别人变,对此我们要进行分类讨论,总结规律

证明:1为奇,n为偶的情况

3个1,一个0,总共4个
A拿到1, B拿到0
A这个时候不可能让自己为0, 因此只有让B为1,那么最后B有最后一个1,可以让A为0
另一种情况,A给自己1让自己为0,B让自己为1,B也赢了

总结出规律之后,就是位运算+贡献思想+特判即可

#include<bits/stdc++.h>
using namespace std;
// A和B初始的数值都是0。
int num[23];
long long a;
void pre(long long a)
{int cnt=1;while(a){if(a&1)num[cnt]++;cnt++;a>>=1;}
}
int main()
{int T;ios::sync_with_stdio(0);cin.tie(0);cin>>T;while(T--){memset(num,0,sizeof(num));int n,sum=0;cin>>n;for(int i=0;i<n;i++){cin>>a;pre(a);sum^=a;}if(!sum)puts("0");else{for(int i=20;i>0;i--)if(num[i]==1){puts("1");break;}else if(num[i]%2==1){if(n%2==1){puts("1");break;}else if(n%2==0){puts("-1");break;}}}}return 0;
}

蓝桥杯2021年第十二届省赛-异或数列_如果a赢, 输出1 如果b赢, 输出-1 如果平局, 输出0-CSDN博客有看不懂的地方可以去看看另一个兄弟的题解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/562449.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

dash 初体验(拔草)

Dash简介 Dash 是一个高效简洁的 Python 框架&#xff0c;建立在 Flask、Poltly.js 以及 React.js 的基础上&#xff0c;设计之初是为了帮助前端知识匮乏的数据分析人员&#xff0c;以纯 Python 编程的方式快速开发出交互式的数据可视化 web 应用。 搭建环境 在学习 Dash 的…

11 Games101 - 笔记 - 几何(曲线与曲面)

11 几何&#xff08;曲线与曲面&#xff09; 贝塞尔曲线 定义 贝塞尔曲线&#xff1a;由控制点和线段组成的曲线&#xff0c;控制点是可拖动的支点。 如图&#xff0c;蓝色为贝塞尔曲线&#xff0c;p1, p2, p3为控制点&#xff0c;曲线和初始与终止端点相切&#xff0c;并且…

【链表】Leetcode 142. 环形链表 II【中等】

环形链表 II 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系…

STC89C52单片机启动--综合案例秒表

代码功能&#xff1a; 1.自动开始计数&#xff0c;一共5个数码管来显示时间。一位数码管显示0-9&#xff0c;对应分度值是0.1s&#xff1b;两位数码管显示00-59&#xff0c;对应分度值1s&#xff1b;两位数码管显示00-59&#xff0c;对应分度值1min&#xff1b;上电后自动开始计…

学习刷题-12

3.22 hw机试【双指针】 Leetcode674 最长连续递增序列 给定一个未经排序的整数数组&#xff0c;找到最长且 连续递增的子序列&#xff0c;并返回该序列的长度。 双指针 一个慢指针一个快指针 慢指针记录递增子序列起点&#xff0c;快指针去寻找还在当前递增子序列的最后一…

忘记密码找回流程请求拦截器-前端

目录 设置找回密码请求拦截器 1.相关参数 2.约定 代码实现 1. 实现思路 2. 实现代码 校园统一身份认证系统&#xff1a; 基于网络安全&#xff0c;找回密码、重新设置密码的流程和正常登录流程中密钥等请求头不一致。 设置找回密码请求拦截器 1.相关参数 clientId 应…

【Android开发】【创建Activity,Activity之间的切换/消息传递】【java】

一、第一个Activity 1.1 创建一个空Activity 1.2 创建一个布局 知识点 在XML中引用一个id&#xff1a;id/id_name 在XML中定义一个id&#xff1a;id/id_name 右键错误&#xff0c;点击Show Quick-Fixes&#xff0c;再点击弹出的Suppress:Add........&#xff0c;错误会被自动修…

【C语言】动态内存分配

1、为什么要有动态内存分配 不管是C还是C中都会大量的使用&#xff0c;使用C/C实现数据结构的时候&#xff0c;也会使用动态内存管理。 我们已经掌握的内存开辟方式有&#xff1a; int val 20; //在栈空间上开辟四个字节 char arr[10] { 0 }; //在栈空间…

利用Base64加密算法将数据加密解密

1. Base64加密算法 Base64准确来说并不像是一种加密算法&#xff0c;而更像是一种编码标准。 我们知道现在最为流行的编码标准就是ASCLL&#xff0c;它用八个二进制位&#xff08;一个char的大小&#xff09;表示了127个字符&#xff0c;任何二进制序列都可以用这127个字符表…

【小沐学AI】智谱AI大模型的一点点学习(Python)

文章目录 1、简介1.1 大模型排行榜 2、智谱AI2.1 GLM2.1.1 模型简介2.1.2 开源代码2.1.2.1 GLM-130B 2.2 ChatGLM2.2.1 模型简介2.2.2 开源代码2.2.2.1 ChatGLM-6B2.2.2.2 ChatGLM3 2.3 CodeGeeX2.3.1 模型简介2.3.2 开源代码 2.4 CogView2.4.1 模型简介2.4.2 开源代码 2.5 Cog…

关于序列化和反序列化

什么是序列化&#xff0c;什么是反序列化 简单来说&#xff1a; 序列化&#xff1a;将数据结构或对象转换成二进制字节流的过程反序列化&#xff1a;将在序列化过程中所生成的二进制字节流转换成数据结构或者对象的过程 为什么要进行序列化 我们要将java对象进行网络传输&a…

Grok-1安装

安装 源代码 huggingface git clone https://github.com/xai-org/grok-1.git # 新建虚拟环境 conda create --prefixD:\CondaEnvs\grok1 python3.11conda activate D:\CondaEnvs\grok1 pip install huggingface_hub[hf_transfer] pip install -U "huggingface_hub[cli]&…