0X01 ——位运算

一:

“与”运算 : &;

“或”运算 : |;

“非”运算 : ~;

“异或”运算:^;

二:补码

(1)32位无符号整数:unsigned int ; 0 ~ 4294967295;

(2)32位有符号整数:int; -2147483648 ~ 2147483647;在计算机用一个数的最高位存放符号, 正数为0, 负数为1.

比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。

 

具体请见:

https://blog.youkuaiyun.com/zl10086111/article/details/80907428?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164983986716780269813706%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=164983986716780269813706&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-80907428.142^v7^control,157^v4^control&utm_term=%E8%A1%A5%E7%A0%81&spm=1018.2226.3001.4187s

三:移位运算;

(1)左移:

把左移运算符(<<)左边的运算数的各二进制位全部左移若干位,移动的位数由左移运算符右边的数指定,高位舍掉,低位补0。

(2)右移:

把右移运算符(>>)左边的运算数的各二进制位全部右移若干位,移动的位数由右移运算符右边的数指定;

对于有符号数,在右移时,符号位将随同移动:

当有符号数为正数时,最高位补0

当有符号数为负数时,最高位也就是符号位为1,最高位补0或者补1,取决于编译系统。(很多系统规定为补1)。

通俗理解:

  • 左移将原数乘以2
  • 右移将原数除以2

举例:

a. 原数: 100
整型是4字节32位,将100以整型的二进制表示
二进制: 00000000 00000000 00000000 01100100

100 >> 2
二进制: 00000000 00000000 00000000 00011001 | 00
解释: | 后面被剔除,前面缺少的两个补0
结果: 25
右移两位相当于除以2,再除以2,结果为25

100 << 2
二进制: 00 | 00000000 00000000 00000001 100100 00
解释: | 前面被剔除,后面缺少的两个补0
结果: 400
左移两位相当于乘以2,再乘以2,结果为400

b. 原数: 75
二进制: 00000000 00000000 00000000 01001011

75 << 25
二进制: 00000000 00000000 00000000 0 | 10010110 00000000 00000000 00000000
解释: | 前面被剔除,后面缺少补0
结果: -1778384896
——这里应当要知道的一点,最高位是符号位,75的最高位为0表示为正数,左移9位后最高位位1表示为负数

觉得理解了,可以尝试一下下面这道题;

求 a 的 b 次方对 p 取模的值。

输入格式 

三个整数 a,b,p ,在同一行用空格隔开。

输出格式

输出一个整数,表示a^b mod p的值。

数据范围

0≤a,b≤10^9
1≤p≤10^9

输入样例:

3 2 7

输出样例:

2

解题思路:

(1)b可用二进制表示为:

所以:

 

 (2)

b & 1运算可以取出b在二进制表示下的最低位,而b >> 1运算可以舍去最低位。

AC代码:

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

typedef long long LL;

int main()
{
    long long a, b, p;
    cin >> a >> b >> p;
    long long ans = 1 % p;
    for(; b ; b >>= 1)
    {
        if(b & 1) ans = ans * a % p;
        a = a * a % p;
    }
    cout << ans << endl;
    return 0;
}

​

还可以尝试一下acwing 90.

四:二进制状态压缩

 

具体可以参考acwing 91.

给定一张 n 个点的带权无向图,点从0∼n−1 标号,求起点 0 到终点 n−1 的最短 Hamilton 路径。

Hamilton 路径的定义是从 0 到 n−1 不重不漏地经过每个点恰好一次。

输入格式

第一行输入整数 n。

接下来 n 行每行 n 个整数,其中第 i 行第 j 个整数表示点 i 到 j 的距离(记为 a[i,j])。

对于任意的 x,y,z,数据保证 a[x,x]=0,a[x,y]=a[y,x] 并且 a[x,y]+a[y,z]≥a[x,z]。

输出格式

输出一个整数,表示最短 Hamilton 路径的长度。

数据范围

1≤n≤20
0≤a[i,j]≤10^7

输入样例:

5
0 2 4 5 1
2 0 6 5 3
4 6 0 8 3
5 5 8 0 5
1 3 3 5 0

输出样例:

18

AC代码:

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

const int N = 20;

int n;
int a[N][N];
int f[1 << N][N];
int main()
{
    cin >> n;
    for(int i = 0; i < n; i ++ )
    {
        for(int j = 0; j < n; j ++ )
        {
            cin >> a[i][j];
        }
    }
    memset(f, 0x3f, sizeof f);
    f[1][0] = 0;
    //终点是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 ++ )/*上一种情况,又因为 j 只能恰好经过一次,所以一定是刚刚经过的,所以在上一时刻“被经过点的状态”对应的二进制的第 j 为应该赋值为 0 ,即 i ^ (1 << j)*/
                { 
                    if((i ^ 1 << j) >> k & 1)
                    {
                        f[i][j] = min(f[i][j], f[i ^ 1 << j][k] + a[k][j]);
                    }
                }
            }
        }
    }
    
    cout << f[(1 << n) - 1][n - 1];
    return 0;
}

五:成对变换

对于非负整数 n : 

当 n 为偶数时,n ^ 1 等于 n + 1;

当 n 为奇数时,n ^ 1 等于 n  - 1;

因此,“0 与1” “2 与3” “4与5” 。。。关于 ^ 1 运算构成“成对变换”。

六:lowbit运算

可以理解为:返回 x 的最后一位1;

应用:统计一下 x 里面 1 的个数

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

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

int lowbit(int x)
{
	return x & (-x);
}

int main()
{
	int x;
	cin >> x;
	int res = 0;
	while(x)
	{
		res ++;
		x -= lowbit(x);
	}
	cout << res << endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值