一、内容

题目入口

二、思路

  • 由于位运算各个位之间都是独立无关的,所以我们只需要计算出每一位经过n道门后变成什么状态(0或1即可)。
  • 计算k(0 <= k < 30) 位上经过n道门后最终变成什么,由于只能再【0,m】里面选取数字进门,所以我们要保住 1 <<k应该小于等于m。
  • 根据位运算可知,若该位是0,经过n道门后变成1,那么若该位是1经过n道门也必定是1。 所以我们分别计算res0,res1, 若res0==res1代表 res0要么是1要么是0,这时候都不用再判断是否超出m。 因为我们可以从该位等于0得出答案。

三、代码

#include <cstdio>
#include <iostream> 
const int N = 1e5 + 5;
using namespace std;
pair<string, int> p[N];
char str[5];
int n, m, t; 
//计算某一位经过n道门后的结果
int calc(int bit, int now) {
	for (int i = 1; i <= n; i++) {
		int x = p[i].second >> bit & 1; //获取bit位上 
		if (p[i].first == "AND") {
			now &= x;
		} else if (p[i].first == "OR") {
			now |= x;
		} else {
			now ^= x;
		} 
	}
	return now;
} 
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%s%d", str, &t);
		p[i] = make_pair(str, t); 
	} 
	int ans = 0;
	int val = 0; //记录的是m以内的数 
	for (int i = 29; i >= 0; i--) {
		int res0 = calc(i, 0); //若是0运算出来位1 那么1必然是1 
		int res1 = calc(i, 1);
		//前面位的数要大一点 
		if (val + (1 << i) <= m && res0 < res1) {
			val += res1 << i;
			ans += res1 << i;
		} else {
			//只要res0 == res1 直接ans加上 
			ans += res0 << i;
		}
	}
	printf("%d", ans);
	return 0;
}