浅谈位运算

目录

  • 位运算前言
  • 位运算应用
    • 1 快速幂
    • 2 最大公约数
    • 3 xor 一些应用
    • 4 其他

位运算前言

程序中所有东西在计算机中都是以二进制储存的。

位运算可以直接操作这些二进制。

所以位运算相对于普通运算要

这些是所有位运算及其优先级:

注意区分逻辑运算和按位运算的区别,逻辑运算视所有 ( eq 0) 的数为 ( exttt{True})(1))。

对于全体运算来说:

运算
逻辑非(not!);按位取反(~ )
乘法(*);除法(/);取模(mod%
加法(+);减法(-
左移(<<);右移(>>
大于(>)小于(<),大于等于(>=),小于等于(<=

转进制IO

一些格式化符:

进制 iomanip 格式化符 printf 格式化符
十进制 dec %d
八进制 oct %o
十六进制 hex %x

注意 cin 的格式化符延长至整个程序,用 dec 恢复!!

位运算应用

  1. 快速幂
  2. 最大公约数

1 快速幂

给定 (a,n) 计算 (a^n)

最朴素的做法当然是 (mathcal{O}(n)) 暴力乘。

typedef long long ll;
ll power(ll a,int n)
{
	ll ans=1;
    for (int i=0;i<n;i++) ans*=a;
    return ans;
}

我们优化一下。

如果我们计算 (7^{31})

我们做一下变式:

(egin{aligned} 7^{31}&=7^{2^0+2^1+2^2+3^3}\ &=7^{1+2+4+16}\ &=7^1 imes 7^2 imes 7^4 imes 7^{16} end{aligned})

我们对于这个变式,考虑二进制拆分。

(31) 正好分成了 (2) 的正整数次幂,是否所有数字都可以呢?

尝试 (7^{11})(11=1+2+8),发现少了个 (4)

(11=(1101)_2),每一个幂都乘此数的每一位即可。

[11=2^{color{red}{1}color{black} imes 1} imes2^{color{red}{1}color{black} imes 2} imes 2^{color{red}{0}color{black} imes 3} imes 2^{color{red}{1}color{black} imes 4} ]

所以这样模拟即可,(mathcal{O}(log n)) 时间复杂度。

其中 (a^n) 可以用一个 ( exttt{base}=a^{n-1})( exttt{base}= exttt{base}* exttt{base}) 求得。

typedef long long ll;
ll qpow(ll a,ll b,ll mod)   //带上取模QAQ
{
	ll ans=1,base=a;
	while (b)                         //没有乘完
	{
		if (b&1) ans*=base,ans%=mod;  //如果这一位为 1,自乘
		base*=base;b>>=1;base%=mod;   //更新 base,进入下一位(b>>=1)
	}
	return ans%mod;    //如果 b=0,那么如果模数为 1 不加 %mod 就会 WA。
}

2 最大公约数

众所周知有辗转相除法:

[gcd(a,b)=gcd(b,amod\,b) ]

朴素算法也就是这个,最坏被卡 (mathcal{O}(log n))

int gcd(int a,int b){return b?gcd(b,a%b):a;}

我们知道有更相减损术:

[gcd(a,b)=gcd(b,a-b) ]

我们能减半尽量要减半,具体看代码即可。

typedef long long ll;
ll gcd(ll a,ll b)  //优化后
{
    if (b==0) return 0;    //特判
    if (a<b) return gcd(b,a); //交换顺序
    if (a==b) return b;    //边界
    if (a&1)    //如果 a 是奇数
    {
        if (b&1) return gcd(b,a-b); //如果 b 也是奇数,只能更相减损
        else return gcd(a,b>>1);  //b 是偶数,减半
    }
    else  //如果 a 是偶数 
    {
        if (b&1) return gcd(a>>1,b);  //b 是奇数,a 减半
        else return 2*gcd(a>>1,b>>1); //都是偶数,一起减半,答案 *2。
    }
}

3 xor 一些应用

首先有个性质:

x^0=xx^1=~x

x^p^p=x,即异或为异或的逆运算。

因异或为异或的逆运算,所以异或是唯一的可逆运算(位运算中)。

所以可以进行简单加密:

  • 两人持有密钥
  • 第一人将自己的数字异或密钥后传至互联网
  • 第二人收到后再次异或密钥,获得原文。

异或还可以做一个交换:

a=a^b;b=a^b;a=a^b;

缺点:

  1. 不能处理同一个变量

总之,别用这种交换

4 其他

  • 取二进制末 (k) 位:a&((1<<k)-1)
  • 取二进制第 (k) 位:(a>>(k-1))&1
  • 取二进制第一个 (1) 与后面的 (0) 组成的数字(( exttt{lowbit})):x&(-x)
  • 将最后一个 (1) 去除:x&=(x-1)
  • 将右数第 (k) 位置 (1)a=(a|(1<<(k-1)))
  • 将右数第 (k) 位置 (0)a&=1<<(k-1)
  • 将右数后 (k) 位置 (1)a&=(1<<(k+1))-1
  • 将右数后 (k) 位置 (0)a&=~((1<<(k+1))-1)
  • 将右数第 (k) 位取反:a^=(1<<k)
  • 将右数后 (k) 位取反:a^=((1<<(k+1))-1)

  • x==-1~x
  • x==0!x
  • x%2x&1
原文地址:https://www.cnblogs.com/CDOI-24374/p/12853980.html