1.1 位运算

1. 补码

由于CPU在进行设计的时候只进行了加法器的设计,所以在它只会处理加法操作,那么问题来了如何进行减法操作呢?例如:A-B,我们可以将其看作是A+(-B)的形式。这样在计算机内部就会出现负数的形式,所以就引入了补码的概念,补码就是对数字进行按位取反再加一的操作,补码在计算机中进行储存负数。

2. 移位运算

1. 左移

就是将二进制中的bit位向左移动一位,低位用0进行填充,高位越界后舍弃。

2. 右移

1. 算数右移

就是将二进制中的bit位向右移动一位,高位用符号位进行填充,低位越界后舍弃。值得注意的一点-3>>1=-2, -3/2 = -1,算数右移按照向下取证的观点,除法运算按照向0取证的观点。

2. 逻辑右移

就是将二进制中的bit位向右移动一位,高位用0进行填充,低位越界后舍弃。

3. 二进制状态压缩

将一个长度为m的bool数组用二进制整数的每一bit位来表示并存储的方法。

常用操作:

1. 取出n的第k位bit的数值:n>>k & 1

2. 取出n的0-k位的数值:n & ((1 << k) -1)

3. 将n的第k位进行取反操作:n ^ (1 << k)

4. 将n的第k位赋值成1:n | (1 << k)

5. 将n的第k位赋值成0:n & (~(1<<k))

4. 成对交换

我们对n进行n^1的操作时发现,如果n为奇数这个操作可以转化成与他相邻的偶数,n ^ 1 ^ 1这样可以得到n本身,这样的数字交换称为成对交换。

5. lowbit运算

lowbit(n)表示非负数的最后一位1表示的数值是多少

inline int lowbit(int n){
      return n & -n;
}

   

 

 

相关练习:

1. 0101 a^b

#include<iostream>

using namespace std;


int qmi(int a, int b, int p){
    int t = 1;
    while(b){
        if(b&1) t = 1ll * t * a % p;
        a = 1ll * a * a % p;
        b >>= 1;

    }
    
    return t % p;
}


int main(){
    int a,b,p;
    cin>>a>>b>>p;
    cout<<qmi(a,b,p)<<endl;
    return 0;
}

2. 0102 64位整数乘法

#include<iostream>


using namespace std;

typedef long long LL;

LL a, b, p;

LL res(LL a, LL b, LL q){
    LL ret = 0, t = 1;
    while(b){
        if(b & 1) ret = (ret + a)  % q;
        b >>= 1;
        a = a * 2 % q; 
    }
    return ret % q;
}

int main(){
    cin>>a>>b>>p;
    
    cout<<res(a,b,p)<<endl;
    return 0;
}

3. POJ1995 Raising Modulo Numbers

#include<iostream>

using namespace std;

int T, H, M;

typedef long long LL;

LL sum;


void calc(int x, int y){
    
    LL t = 1;
    while(y){
        if(y & 1) t = (t * x) % M;
        x = 1ll * x * x % M;
        y >>= 1;
    }
    sum = (sum + t) % M;
    
}

int main(){
    cin>>T;
    while(T--){
        cin>>M>>H;
        sum = 0;
        for(int i = 0; i < H; ++i){
            int l, r;
            cin>>l>>r;
            calc(l, r);
        }
        cout<<sum <<endl;
    }
    
    
    return 0;
}

4. 0104 起床困难综合症

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;


typedef pair<string, int> PSI;
const int N = 1e5+10, M = 1e9;

PSI op[N];

int n, m;




int calc(int bit, int num){
    
    for(int i = 1; i <= n; ++i)
        if(op[i].first == "AND") num &= op[i].second >> bit;
        else if(op[i].first == "OR") num |= op[i].second >> bit;
        else num ^= op[i].second >> bit;
    return num & 1;
}

int main(){
	#ifdef _DEBUG
		freopen("input.txt", "r", stdin);
		freopen("output.txt", "w", stdout);
	#endif
    cin>>n>>m;
    for(int i = 1; i <= n; ++i)
        cin>>op[i].first>>op[i].second;
    

    int res = 0, ans = 0;
    for(int i = 29; ~i; --i){
        int l = calc(i, 0), r = calc(i, 1);
		#ifdef _DEBUG
        cout<<i<<' ' << l << ' '<<r<<endl;
		#endif
        if(res + (1 << i) <= m && l < r){
            ans += r << i;
            res += 1 << i;
        }
        else ans += l << i;
    }
    
    cout<<ans<<endl;
    return 0;
        
}

5. 0103 最短Hamilton路径

#include<iostream>
#include<cstring>

using namespace std;

const int N = 1 << 20, M = 20;

int f[N][M], path[M][M];

int n;


int main(){
    cin>>n;
    for(int i = 0; i < n ;++i){
        for(int j = 0; j < n; ++j){
            cin>>path[i][j];
        }
    }
    
    
    memset(f, 0x3f, sizeof f);
    
    f[1][0] = 0;
    
    for(int i = 1; i < (1 << n); ++i){
        for(int j = 0; j < n; ++j){
            if(i & (1 << j)){
                for(int k = 0; k < n; ++k){
                    if(((i - (1 << j)) & (1 << k))){
                        f[i][j] = min(f[i][j], f[i - (1<<j)][k]+path[k][j]);
                    }
                }
            }
        }
    }
    
    
    cout<<f[(1<<n)-1][n-1]<<endl;
    return 0;
    
    
}

  

 

 

 

 

 

posted @ 2019-10-10 16:49  楓羽  阅读(731)  评论(0编辑  收藏  举报