【阅读笔记】0x01 位运算

1.补码表示: ~x=-1-x

2.自然溢出:unsigned long long 自动对2^32取模,可以用来hash

3.基本位运算操作:

左移:1<<n=2^n

n<<1=2n,n<<2=4n,n<<3=8n。。。

算术右移:n>>1=n/2 ,n>>4=n/16。。。算术右移=除以2向下取整 e.g. (-3) >> 1 = -2,3>>1=1

P.S. 整数/2 = 除以2向0取整 e.g. (-3)/2=-1 , 3/2=1

tips:以下二进制以0为最低位,即k从0开始。

取出整数n在二进制下的第k位:(n>>k)&1

取出整数n在二进制下的第0~k-1位(后k位):n&((1<<k)-1)

把整数n在二进制表示下的第k位取反:n^(1<<k)

把整数n在二进制表示下的第k位赋值为1:n|(1<<k)

把整数n在二进制表示下的第k位赋值为0:n&(~(1<<k))

以上常用于把一个n维bool数组压缩成一个n维二进制整数,即状态压缩,常用于状压DP

注意符号的运算优先级:加减(+ -)>移位(>> <<)>比较大小(> < == !=)>位与(&)>异或(^)>位或(|)

可以直接每个运算符都加一个括号来提高正确性。

成对变换:n为偶数 n^1=n+1 ; n为奇数 n^1=n-1 so“0 1”,“2 3”构成成对变换,常用于存图中的边与其反向边。

lowbit: lowbit(x)=x&-x 返回x在二进制表示下的最低位的1及其后面的0构成的数值。是树状数组的核心。

4.快速幂 O(logn)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int main(){
    ll a,b,p;
    scanf("%lld%lld%lld",&a,&b,&p);
    ll mul=1;
    for(;b;b>>=1){
        if(b&1) mul=(mul*a)%p;
        a=(a*a)%p;
    }
    printf("%lld",mul%p);
    return 0;
}

5.64位整数乘法 O(logn)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int main(){
    ll a,b,p;
    scanf("%lld%lld%lld",&a,&b,&p);
    ll mul=0;
    for(;b;b>>=1){
        if(b&1) mul=(mul+a)%p;
        a=(a*2)%p;
    }
    printf("%lld",mul%p);
    return 0;
}

 

猜你喜欢

转载自www.cnblogs.com/Loi-Brilliant/p/9417598.html