位运算

位运算

Part1. 基础运算

 &     与     两个位都为1时,结果才为1                                                
 |     或     两个位都为0时,结果才为0                                            
 ^     异或    两个位相同为0,相异为1                                                  
 ~     取反    0变1,1变0                                                         
 <<    左移    各二进位全部左移若干位,高位丢弃,低位补0                                     
 >>    右移    各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)

Part2. 混合运算

(n >> k) & 1   取 n 的第 k 位
n & ((1 << k) - 1)  取 n 的后 k 位
n ^ (1 << k)   将 n 的第 k 位取反
n | (1 << k)   将 n 的第 k 位改为 1
n & (~(1 << k)) 将 n 的第 k 位改为 0 

Part3. 其他函数

int __builtin_popcount(unsigned int x) :返回 x 的二进制中 1 的个数。

int __builtin_ffs(int x) :返回 x 的二进制末尾最后一个 1 的位置,位置的编号从 1 开始(最低位编号为 1 )。当 x0 时返回 0

int __builtin_clz(unsigned int x) :返回 x 的二进制的前导 0 的个数。当 x0 时,结果未定义。

int __builtin_ctz(unsigned int x) :返回 x 的二进制末尾连续 0 的个数。当 x0 时,结果未定义。

Part4. 例题

[NOI2014] 起床困难综合症

题目传送门

我们发现,直接找最大值必定 T 飞,考虑使用二进制。

那么对于这个题,二进制有点在于什么地方呢?

很显然,我们在十进制中,想让一个数最大,是不是先判断最高位,最高位最大就一定最大。在二进制中也是如此。而且二进制一个位上就两种可能,要么是一要么是零。

我们可以随便搞两个变量记录二进制全 \(0\) 和全 \(1\) 经过门之后的样子。

然后从最高位开始找就可以了。

注释代码:

#include<bits/stdc++.h>

#define rint register int
#define endl '\n'
#define int long long

using namespace std;

const int N = 1e5 + 5;

int n, m;
int bit1 = 0, bit2 = -1;
//这两个数用来预处理,一个是全零,一个是全一
int ans;

signed main()
{
    cin >> n >> m;
    
    for (rint i = 1; i <= n; i++)
    {
		string s;
		int a;
		cin >> s >> a;
		if (s[0] == 'A')
		{
			bit1 &= a;
			bit2 &= a;
		}
		if (s[0] == 'O')
		{
			bit1 |= a;
			bit2 |= a;
		}
		if (s[0] == 'X')
		{
			bit1 ^= a;
			bit2 ^= a;
		}
	}
	
	//从最高位开始枚举
	for (rint i = 32; i >= 0; i--)
	{
		if ((bit1 >> i) & 1)
		/*
		如果对于当前位而言
		bit1 出来为 1
		累计答案
		*/
		{
			ans += (1ll << i);
		}
		else if ((bit2 >> i) & 1)
		{
			if((1ll << i) <= m)
			{
				m -= 1ll << i;
				ans += 1ll << i;
			}
		}
	}
	
	cout << ans << endl;
	
	return 0;
}
posted @ 2023-10-21 15:42  PassName  阅读(13)  评论(0编辑  收藏  举报