按位枚举确定答案, 起床困难综合症
按位枚举确定答案
在二进制数中, 高位取1所产生的数比所有低位都取1形成的数都大, 即 $ 1 << n > (1 << n) - 1 $
可以在确定答案的时候运用贪心的思想, 即能在高位取1就在高位取1
起床困难综合征
给定 $n$ 个运算, 每个运算中有两个参数, 操作 $ (or/xor/and) $ 和数 $(x_{i})$
求当初始数 $\leq m$ 时, 依次按顺序经过这 $n$ 次运算, 最终所能产生的最大值
位运算在二进制表示下不进位, 即参加位运算的各个位之间是独立无关的
所以最终所求的最大值 $ans$ 的每一位只与每个运算的数 $x_{i}$ 有关, 与其余位无关, 所以可以从高位往低位进行枚举, 依次考虑每一位应该填1还是填0
其中填1时必须满足的条件是:
1.当前位能填1, 即填了1不会超过范围 $m$
2.当前位填1, 最终产生的收益大于填0, 即填1后经过这 $n$ 次变换还是1, 填0后经过这 $n$ 次变换是0
否则填1不如填0, 因为因为填0能产生更高的收益( $\geq $ 填1的)并且不占用范围空间
像这样依次确定了 $ans$ 的每一位, 最终就得到了 $ans$
pair<string, int> ops[N]; //n次操作
//计算第bit位在经过n次运算后得到的数(1或0)
int calc(int bit, int now) {
for(int i = 0; i < n; i++) {
int x = ops[i].second >> bit & 1; //取出当前数xi的第bit位
if(ops[i].first == "AND") now &= x; //与上
else if(ops[i].first == "OR") now |= x; //或上
else now ^= x; //异或上
}
return now; //返回经过这n次运算后的第bit位的值(1或0)
}
//求解, 从高位向低位依次枚举, 判断应该填1还是0
void solve() {
//pay表示初始值(当前用的数), ans表示变换后的最大值
int pay = 0, ans = 0;
//从29开始从大到小枚举, 因为2^30已经超过了m的范围
for(int bit = 29; bit >= 0; bit--) {
int ans0 = calc(bit, 0); //当前位填0的收益
int ans1 = calc(bit, 1); //当前位填1的收益
//判断是否满足填1的条件, 否则填0
if(pay + (1 << bit) <= m && ans1 > ans0) pay += 1 << bit, ans += ans1 << bit;
else ans += ans0 << bit;
}
cout << ans;
}

浙公网安备 33010602011771号