浅谈异或运算符的应用及相关题目题解
一、异或运算符(^)
1.定义:
异或可以理解为将两个数分别转化成二进制数,逐位比对,相同得到0,不同得到1,最后再换回十进制的运算。异或也叫半加运算,可以推出其运算法则相当于不带进位的二进制加法。
2.几条性质:
(1) a^a=0;
(2) 交换律:ab=ba;
(3) 结合律:abc=a(bc)=(ab)c;
(4) d=abc可以推出a=dbc;
(5) 一个数异或另一个数两次等于原数:abb=a.
二、相关题目
1.[洛谷P1161]开灯
Description
-在一条无限长的路上,有一排无限长的路灯,编号为1,2,3,4,……。
每一盏灯只有两种可能的状态,开或者关。如果按一下某一盏灯的开关,那么这盏灯的状态将发生改变。如果原来是开,将变成关。如果原来是关,将变成开。
在刚开始的时候,所有的灯都是关的。
小明每次可以进行如下的操作:指定两个数,a,t(a为实数,t为正整数)。将编号为[a],[2a],[3a],……,[t*a]的灯的开关各按一次。其中[k]表示实数k的整数部分。在小明进行了n次操作后,小明突然发现,这个时候只有一盏灯是开的,小明很想知道这盏灯的编号,可是这盏灯离小明太远了,小明看不清编号是多少。
幸好,小明还记得之前的n次操作。于是小明找到了你,你能帮他计算出这盏开着的灯的编号吗?
-输入格式:第一行一个正整数n,表示n次操作。接下来有n行,每行两个数,ai,ti。其中ai是实数,小数点后一定有6位,ti是正整数。
-输出格式:仅一个正整数,那盏开着的灯的编号。
记T=t1+t2+t3+……+tn。
对于30%的数据,满足T<=1000
对于80%的数据,满足T<=200000
对于100%的数据,满足T<=2000000
对于100%的数据,满足n<=5000,1<=ai<1000,1<=ti<=T
数据保证,在经过n次操作后,有且只有一盏灯是开的,不必判错。
Solution
1.题目看起来像是模拟,但数据规模很迷,我们选择使用异或运算;
2.我们让ans异或每次操作的编号,由性质5可知,当同一编号的灯被偶数次操作时对ans的数值并不影响;
3.因为数据保证只有一盏灯是亮的,所以输出ans即可;
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int main(){
int i,j,n,t,ans=0;
double d;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%lf%d",&d,&t);
for(j=1;j<=t;j++) ans^=(int)floor(j*d); //对每次操作的灯的编号进行异或运算,注意向下取整floor()返回值是double型;
}
printf("%d",ans);
return 0;
}
2.[HDU2095]find your present (2)
Description
-In the new year party, everybody will get a "special present".Now it's your turn to get your special present, a lot of presents now putting on the desk, and only one of them will be yours.Each present has a card number on it, and your present's card number will be the one that different from all the others, and you can assume that only one number appear odd times.For example, there are 5 present, and their card numbers are 1, 2, 3, 2, 1.so your present will be the one with the card number of 3, because 3 is the number that different from all the others.
-Input
The input file will consist of several cases.Each case will be presented by an integer n (1<=n<1000000, and n is odd) at first. Following that, n positive integers will be given in a line, all integers will smaller than 2^31. These numbers indicate the card numbers of the presents.n = 0 ends the input.
-Output
For each case, output an integer in a line, which is the card number of your present.
Solution
1.注意:“you can assume that only one number appear odd times”,题目即可理解为:有2k+1个数字,其中有k个相同的数和一个不同的数,输出不同的数;
2.显然,做法与上题相同,用ans异或每一个数即可,最后留下的ans就是单个的数字;
3.“n = 0 ends the input.”:多组数据,加一个对0的特判即可,注意每次操作时对ans清零;
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int main(){
int i,j,n,t,ans;
while(scanf("%d",&n)==1&&n) //对读入0的特判
{
ans=0;
for(i=1;i<=n;i++){
scanf("%d",&t);
ans^=t;
}
printf("%d\n",ans);
}
return 0;
}