一些关于二进制位运算的奇特性质(持续跟新)

一些关于位运算的奇特性质(持续跟新)

一、异或 ⨁ \bigoplus

异或,又称不进位加法,或者不借位减法。
性质:
1. 1. 1.满足交换律和结合律
2. 2. 2. a ⨁ a = 0 a\bigoplus a =0 aa=0 a ⨁ 0 = a a\bigoplus 0=a a0=a.
3. 3. 3. i f   a ⨁ b = c if \ a\bigoplus b = c if ab=c t h e n   a = b ⨁ c then \ a = b\bigoplus c then a=bc.

2、 3合起来使得 ⊕ \oplus 满足可减性。不过运算时要把减号换成 ⊕ \oplus 。于是我们在实际运算中,完全可以把异或看成加法和减法。这使得它能够做前缀和,以及
Acwing-高斯消元解异或线性方程组

由于其不进位加法的性质,在异或操作时,对于二进制位上对应的两个数,我们如果要想使其增大,需要尽量选择不一样的;如果想使其减小,那么必须对应位置上都是1和1。

二、与 & \& &

1. 1. 1.满足交换律和结合律
2. 2. 2. a & b ≤ min ⁡ ( a , b ) a\&b \le \min(a,b) a&bmin(a,b)

这是因为,当我们对一个二进制位上进行&时,答案不会变得更大。

三、或 ∣ |

这个运算用的不多。
不过有一个简单的性质: a ∣ b ≥ max ⁡ ( a , b ) a|b\ge\max(a,b) abmax(a,b)

四、一些神奇的推论

1.和加法的联系
a + b = a ⊕ b + 2 a & b = a & b + a ∣ b a+b=a\oplus b +2a\&b=a\&b + a|b a+b=ab+2a&b=a&b+ab

证明:如果不进位,那么结果就是 a ⊕ b a\oplus b ab。考虑进位,就是两个数二进制位上同时为 1 1 1,并且左移一位得到的数。两个相加就可以得到结果。 a & b + a ∣ b a\&b + a|b a&b+ab中,两个数二进制位上同时为 1 1 1时则进位,不是则不进位。

这个性质有两个例题:CF672A
题意:给出两个数 2 ≤ s ≤ 1 0 12 2\le s \le 10^{12} 2s1012 0 ≤ x ≤ 1 0 12 0 \le x\le 10^{12} 0x1012,求有序正整数对 ( a , b ) (a,b) (a,b)有多少对。其中 ( a , b ) (a,b) (a,b)满足:
a + b = s a ⊕ b = x \begin{aligned} &{a+b=s}\\ &{a\oplus b = x} \end{aligned} a+b=sab=x
为了方便理解,我们设 d p [ i ] dp[i] dp[i]为只考虑前 i i i位二进制位有多少种方案。
我们容易求出 a & b a\&b a&b,然后对于 a & b a\&b a&b a ⊕ b a\oplus b ab二进制同一位上的两个数,可以发现:

如果 a & b a\&b a&b的第 i i i位为 1 1 1,那么 a a a b b b这两位上必为1。因此,如果 ( a ⊕ b ) & ( 1 < < ( i − 1 ) ) = 1 (a\oplus b)\&(1<<(i-1))=1 (ab)&(1<<(i1))=1那么没有答案,否则 d p [ i ] = d p [ i − 1 ] dp[i]=dp[i-1] dp[i]=dp[i1]
如果 a & b a\&b a&b的第 i i i位为 0 0 0,那么当 a ⊕ b a\oplus b ab 1 1 1时, d p [ i ] = d p [ i − 1 ] ∗ 2 dp[i]=dp[i-1]*2 dp[i]=dp[i1]2
,否则 d p [ i ] = d p [ i − 1 ] dp[i]=dp[i-1] dp[i]=dp[i1]

这个题还有些小坑。比如当 s < x s<x s<x或者 ( s − x ) % 2 ≠ 0 (s-x)\%2\ne0 (sx)%2=0时直接输出 0 0 0
还有就是,如果定义 1 < < 35 1<<35 1<<35,那么 1 1 1 i n t int int会溢出。我们需要用 1 l l < < 35 1ll<<35 1ll<<35
最后一个坑点,题目要求的是正整数对,而我们这种考虑方案可能会选到 0 0 0。如果 a = 0 a=0 a=0,那么 a & b a\&b a&b必然为 0 0 0。因此当 a & b = 0 a\&b=0 a&b=0时我们需要减去这种方案。

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
using namespace std;

const double eps = 1e-10;
const double pi = acos(-1.0);
const int maxn = 1e6 + 10;

ll s,x;

void solve(){
	scanf("%lld%lld",&s,&x);
	if((s-x)%2 || s < x){
		puts("0");
		return;
	}
	s = (s-x)>>1;//s表示(a&b)
	ll t = max(s,x),ans = 1;
	int len = 0;
	while(t) t>>=1,len++;
	for(int i = 1; i <= len; i++){
		if((s&(1ll<<(i-1))) && (x&(1ll<<(i-1))) ){
			puts("0");
			return;
		}
		if(!(s&(1ll<<(i-1))) && (x&(1ll<<(i-1))) ) ans <<= 1ll;
	}
	if(s == 0) ans -= 2;
	printf("%lld\n",ans);
}

int main()
{
	solve();
	return 0;
}

2.找最低位(最右边的 1 1 1)
l o w b i t ( x ) = x & ( − x ) lowbit(x)=x\&(-x) lowbit(x)=x&(x)
3.取出第 i i i位(从右往左)
a & ( 1 < < ( i − 1 ) ) a\& \left(1<<(i-1)\right) a&(1<<(i1))
4. a − 1 a-1 a1会使 a a a二进制位上的第一个出现的 1 1 1变成 0 0 0,而这个 1 1 1右边的 0 0 0 全部变成 1 1 1

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值