位运算

位运算

基本的算术位运算:

异或

and,&

or,|

not,~

xor

  • 补码

32位无符号整数unsigned int:

直接把这32位编码C看作32位二进制数N。

 

32位有符号整数int:

以最高位为符号位,0表示非负数,1表示负数。

对于最高位为0的每种编码C,直接看作32位二进制数S。

 

n为非负数,n的符号位(即最高位)为0,原码、反码、补码相同。

n为负数,n的符号位(即最高位)为1,反码为原码除最高位取反,补码为反码加一。

  • 移位运算

左移

1<<n=2nn<<1=2n

右移

n>>1=n/2

 

【例题】a^b(快速幂)

代码如下:

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

int main(){
    int a,b,p;
    cin>>a>>b>>p;
    ll ans=1%p;

    for(;b;b>>=1){
        if(b&1)ans=(ll)ans*a%p;
        a=(ll)a*a%p;
    }

    cout<<ans;
    return 0;
}

 

 

【例题】64位整数乘法

方法一:类似于快速幂的思想

代码如下:

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

int main(){
    ll a,b,p,ans;
    cin>>a>>b>>p;

    for(;b;b>>=1){
        if(b&1)ans=(ans+a)%p;
        a=(a+a)%p;
    }

    cout<<ans;
    return 0;
}

 

 

方法二:long double做法

a*b mod p=a*b-(a*b/p)*p

 

代码如下:

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

int main(){
    ll a,b,p,c,ans;
    cin>>a>>b>>p;

    a%=p;b%=p;
    c=(ld)a*b/p;
    ans=a*b-c*p;

    if(ans<0)ans+=p;
    else if(ans>=p)ans-=p;

    cout<<ans;
    return 0;
}

 

  • 二进制状态压缩

操作

运算

取出整数n在二进制表示下的第k位

(n>>k)&1

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

n&((1<<k)-1)

把整数n在二进制表示下的第k位取反

n xor (1<<k)

对整数n在二进制表示下的第k位赋值为1

n|(1<<k)

对整数n在二进制表示下的第k位赋值为0

n&(~(1<<k))

 

【例题】最短Hamilton路径(状态压缩DP)

使用一个n位的二进制数:若其第i(0≤i<n)位为1,则表示第i个点已经被经过,反之未被经过。

F[i,j](0≤i<2n,0≤j<n):“点被经过的状态”对应的二进制数为i,且目前处于点j时的最短路径。

 

初始值:F[1,0]=0,F数组的其他值设为无穷大。

答案:F[(1<<n)-1,n-1]

 

状态转移方程:F[i,j]=min{F[i xor (1<<j),k]+weight(k,j)}

0≤k<n并且((i>>j)&1)=1

 

代码如下:

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

int n;
int f[1<<20][20];
int w[20][20];

int main(){
    cin>>n;
    memset(f,0x3f,sizeof f);
    f[1][0]=0;

    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            cin>>w[i][j];

    for(int i=1;i<1<<n;i++)
        for(int j=0;j<n;j++)if(i>>j&1)
            for(int k=0;k<n;k++)if(i>>k&1)
                f[i][j]=min(f[i][j],f[i^1<<j][k]+w[k][j]);

    cout<<f[(1<<n)-1][n-1];
    return 0;
}

 

运算符优先级从高到低的顺序:

加减

移位

比较大小

位与

异或

位或

+,-

<<,>>

>,<,==,!=

&

xor

|

 

  • 成对变换

对于非负整数n:

n为偶数时,n xor 1等于n+1

n为奇数时,n xor 1等于n-1

“0与1”、“2与3”、“4与5”……关于xor 1运算构成“成对变换”。

 

  • lowbit运算

lowbit(n)取出非负整数n在二进制表示下最低位的1以及它后边的0构成的数值。

lowbit(n)=n&(~n+1)=n&(-n)

 

作用: 

①配合Hash可以找出整数二进制表示下所有是1的位,所花费的时间与1的个数统计。

②是树状数组中的一个基本运算。

 

const MAX_N=1<<20
int H[MAX_N+1];

for(int i=0;i<=20;i++)H[1<<i]=i;
while(cin>>n){
    while(n>0){
        cout<<H[n&-n]<<‘ ’;
        n=n&-n;
    }
}

 

 

posted @ 2019-09-22 11:15  小仙女本仙  阅读(524)  评论(0编辑  收藏  举报