概述
写在前面
异或概念用在这里不提及了,若不懂的话可自行了解
一、异或的性质
异或是一种基于二进制的位运算,用 ^ 表示,其运算法则是对运算符两侧数的每一个二进制位,同值取0,异值取1。
简单理解就是不进位加法,如1+1=0,,0+0=0,1+0=1。(这点很重要)
性质
- 交换律 可任意交换运算因子的位置,结果不变
- 2、结合律(即(a^b)^c == a^(b^c))
- 3、对于任何数x,都有x^x=0,x^0=x,同自己求异或为0,同0求异或为自己
- 4、自反性 A ^ B ^ B = A ^ 0 = A ,连续和同一个因子做异或运算,最终结果为自己
PS:关于异或的性质,大家可以自行找几个数试一试
二、异或的作用
1.交换二数值不需要第三数
直接看代码就知道了:
a = 9;//赋值
b = 11;
a=a^b; //1001^1011=0010
b=b^a; //1011^0010=1001
a=a^b;
//0010^1001=1011
a = 11;//运行结果
b = 9;
2.判断奇偶更简单高效的做法
奇数二进制的最低位一定是1,偶数二进制的最低位一定是0,
SO:
a^b==1?偶数:奇数 //异或运算判断
a^b==0?偶数:奇数 //与运算判断
三、找出唯一成对的那个数
1-n这n个数中,只有唯一的一个元素值重复,其它均只出现 一次。每个数组元素只能访问一次,设计一个算法,不用辅助存储空间,将其找出来.
题解:
将所有的数全部异或(1^2^…^1000^p,p为重复的数),得到的结果与(1^2^3^…^1000)的结果进行异或,得到的结果就是重复数。 即(1^2^...^1000^p)^(1^2^3^...^1000),由于有结合律、交换律存在,可以这么调整为(1^1^2^2^...^1000^1000^p)
那结果当然就是p了
四、找出出现奇数次的数
一个数组存放若干整数,一个数出现奇数次,其余数均出现偶数次,找出这个出现奇数次的数.
结果=a[0]^a[1]^...^a[n-1]
因为奇数个数字连续异或之后是自己,偶数个数连续异或后为0,而奇数个数自己和0异或还是自己(233)
源码:
#include<bits/stdc++.h>
using namespace std;
int a[10005],n;
int main()
{
int m=0;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) m^=a[i];
cout<<m<<endl;
}
三、习题
取火柴游戏
输入 k 及 k 个整数 n 1 ,n 2 ,…,n k ,表示有 k 堆火柴棒,第 i 堆火柴棒的根数为 n i 。接着便是和计算机对弈游戏,取火柴的规则如下:每次可以从一堆中取走若干根火柴,也可以将一堆全部取走,但不允许跨堆取,也不允许不取。
谁取走最后一根火柴算谁胜利。
例如,k=2,n 1 =n 2 =2,A 代表你,P 代表计算机,若决定 A 先取:
A:(2,2)→(1,2) // 从一堆中取一根
P:(1,2)→(1,1) // 从另一堆中取一根
A:(1,1)→(1,0)
P:(1,0)→(0,0) //P 胜利
如果决定 A 后取:
P: (2,2)→(2,0)
A: (2,0)→(0,0) //A 胜利
又如 k=3,n 1 =1,n 2 =2,n 3 =3,A 决定后取:
P: (1,2,3)→(0,2,3)
A: (0,2,3)→(0,2,2)
A 已将游戏归结为(2,2)的情况,不管 P 如何取 A 都必胜。
编一个程序,在给出初始状态之后,判断是先取必胜还是先取必败,如果是先取必胜,请输出第一次该如何取。如果是先取必败,则输出“lose”。
输入
第一行,一个正整数k
第二行,k个整数n1,n2,…,nk
输出
如果是先取必胜,请在第一行输出两个整数a,b,表示第一次从第b堆取出a个。第二行为第一次取火柴后的状态。如果有多种答案,则输出< b,a >字典序最小的答案(即b最小的前提下a最小)。
如果是先取必败,则输出“lose”。
样例输入
【输入样例1】
3
3 6 9
【输入样例2】
4
15 22 19 10
样例输出
【输出样例1】
4 3
3 6 5
【输出样例2】
lose
提示
样例1解释
表示第 1 次从第 3 堆取 4 个出来必胜
第 1 次取后的状态
题解:
先求出所有元素的异或m,不为0,则必胜;m依次异或得到的值比当前元素小,则变成当前值即可;
源码:
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int k,n[N],sg;
int main()
{
scanf("%d",&k);
for(int i=1;i<=k;i++)
{
scanf("%d",&n[i]);
sg^=n[i];//求异或和
}
if(sg==0)
{
puts("losen");
return 0;
}
for(int i=1;i<=k;i++)
{
if((n[i]^sg)>=n[i]) continue;//可以拿走几根火柴
printf("%d %dn",n[i]-(n[i]^sg),i);//答案
n[i]^=sg;//ai变为ni^X, 拿走了ni - ni^X
break;
}
for(int i=1;i<=k;i++)
printf("%d%c",n[i],i==k?'n':' ');
return 0;
}
最后
以上就是乐观自行车为你收集整理的异或的性质、用途、习题写在前面一、异或的性质二、异或的作用三、习题的全部内容,希望文章能够帮你解决异或的性质、用途、习题写在前面一、异或的性质二、异或的作用三、习题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复