异或运算

知识点:

  1. 异或就是无进位相加。每一位对应相加,进位被舍弃。
    A 01101110
    B 10011101
    ->11110011
    从低往高位:0加1是1,1加0是1,1加1有一个进位,结果为零,对于下一位,忽略进位,1加1还是0,有一个进位,再下一位,忽略进位,1加0结果为1....

  2. 异或运算满足交换律,结合律。同一批数字无论异或顺序如何,最终结果都是一个。
    image-20201212190410230
    无进位相加,最终结果只和每一行1的数量有关。偶数个1结果为0,奇数位1结果为1.
    相加时每一位的1的数量不变,结果只和1的数量有关

  3. 0 ^ n=n(无进位相加),n^n=0.(每一位0+0=0,1+1=0(进位舍弃))。

  4. 设有一批数的异或结果为x(异或和),从中抽取任意位数,他们新的异或结果为y,那么剩余没被选中的数异或的结果为x^y。
    条件:a^b=c --> a=c^b, b=c^a(满足交换律结合律)
    总体异或结果为a,某一部分异或结果为b,如何得到剩下的部分:a ^ b.
    image-20201212190410230
    将黑球视为1,白球视为0。那么题目可以看为0+1或1+01,0+0或1+10。与异或逻辑一致。那么题目就变成了从a个0和b个1中随机选两个数,将这两个数的异或结果放回袋子中,那么结果也就相当于这a+b个数整体的异或结果。
    最终结果就相当于这些球的异或和。只和黑球的数目(1的数量)有关。

题目:


1. 异或运算交换两个数

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int a,b;
	cin>>a>>b;
	a=a^b;
	b=a^b;
	a=a^b;
	cout<<a<<" "<<b<<endl;
	return 0;
}

设a=甲,b=乙。
第一行 a=甲 ^ 乙;
第二行 b=甲 ^ 乙 ^ 乙 = 甲 ^ 0=甲
(异或运算什么顺序都可以,满足交换律结合律)
第三行 a=甲 ^ 乙 ^ 甲 = 0 ^ 乙=乙

异或运算交换位置两个数必须占有不相同的内存区域。否则同一位置的数会被刷成0.
如果这个交换方式在数组中,当i和j都指向0下表时,这个语句就变成了,arr[0]=arr[0]^arr[0],结果就是arr[0],无论原来的数是多少,最后都会被刷成0。在进行之后的交换操作时也就没有了意义。


2. 不用任何判断语句和比较操作,返回两个数的最大值

二进制,最高位处于31位,最低位处于0位,最高位如果为1的话代表是负数,如果是0代表非负数。

如果这个数是n,带符号(或不带符号)右移31位(让符号位移动到0位置上)
在和0与一下(负数得到1,非负数得到0)(如果是不带符号右移,前面拿0补齐,那么不用和1再次与一下。因为负数移动到最后必然是前31位为0,第0位为1)(如果想要负数得到0,非负的到1,和以将&改为^)。

有溢出风险:

#include<bits/stdc++.h>
using namespace std;
#define int long long

signed main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int a,b;
	cin>>a>>b;
	int c=a-b;//如果a比b大,会输出a.
	int a1=(c>>31&1)^1;//判断符号,如果为负那么和1异或一下使a1变为0。从而输出最大值,如果去掉异或1,就会变成输出最小值。
	int b1=a1^1;
	cout<<a*a1+b*b1<<endl;
	return 0;
}
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'

int findMax(int a, int b) {
	int c = a - b;
	int signA = (a >> 31) ^ 1; // a的符号
	int signB = (b >> 31) ^ 1; // b的符号
	int signC = (c >> 31) ^ 1; // c的符号
	
	int diffAB = signA ^ signB; // 判断a和b的符号是不是不一样
	int sameAB = diffAB ^ 1; // 判断a,b符号是不是一样
	
	int returnA = diffAB * signA + sameAB * signC;
	//如果ab符号不一样并且a为非负或ab符号一致并且c是正的。那么returna就是1,
	int returnB = returnA ^ 1;
	
	return a * returnA + b * returnB;
}

int main() {
	int a, b;
	cin >> a >> b;
	cout << findMax(a, b) << endl;
	return 0;
}
posted @ 2024-04-06 11:42  miao-jc  阅读(23)  评论(0编辑  收藏  举报