解法思想:
位运算只关注当前进行运算的一位,对其他位无影响。对于输入的初始攻击x,需要进行n次op运算,得到最大攻击力。把最后的输出以二进制表示,即我们希望输出的最大攻击力有尽可能多的1。
对于初始攻击x,假设一共有k位,每一位只有0或1两种取值。我们把每一位单独拿出来做n次运算。来确定该位应该填0还是1。依次从高位到低位确定。
比如:对于一个4位的数_ _ _ _,我们需要进行3次op运算,假设最高位第3位分别是0或1的两种情况,op[i]运算对应参数为t[i],则对t[i]>>3&1,这里我们只关心参数t[i]对应需要运算的一位,其他全部置0,所以与1进行与运算。0和1分别做完n次运算后的结果为res0和res1,谁大取谁,对res<<3得到最大攻击力该位的数值。其他位计算同理。
这里还有两个约束条件:
1.若res0<res1,我们需要保证当初始攻击该位取1时不超过初始攻击上限m。
2.若res0>res1,该位取0。
————————————————
原文链接:https://blog.csdn.net/weixin_45774311/article/details/120827430
https://www.acwing.com/solution/content/15383/
/* 按位或:OR 为按位或运算,处理两个长度相同的二进制数,两个相应的二进制位中只要有一个为 1,则该位的结果值为 1,否则为 0。运算符 (|) 按位异或:XOR 为按位异或运算,对等长二进制模式或二进制数的每一位执行逻辑异或操作。如果两个相应的二进制位不同(相异),则该位的结果值为 1,否则该位为 0。运算符(^)。 按位与:AND 为按位与运算,处理两个长度相同的二进制数,两个相应的二进制位都为 1,该位的结果值才为 1,否则为 0。运算符(&)。 取反运算:参加运算的一个数据,按二进制位进行“取反”运算。运算符(~)。 左移运算:将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。左移一位相当于该数乘以2。运算符(<<)。 右移运算:将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。右移一位相当于该数除以2。运算符(>>)。 */ #include<stdio.h> const int N=100005; int n,m; int ans; int t[N]; short op[N]; char str[4]; bool calc(bool x,int j) { for(int i=0;i<n;i++) { if(op[i]==1) x|=t[i]>>j&1; else if(op[i]==2) x^=t[i]>>j&1; else x&=t[i]>>j&1; } return x; } int main() { scanf("%d %d",&n,&m); for(int i=0;i<n;i++) { scanf("\n%s %d",str,t+i); if(*str=='O') op[i]=1; else if(*str=='X') op[i]=2; else op[i]=3; } for(int i=29;~i;i--) { if(1<<i<=m) { bool x=calc(0,i),y=calc(1,i); if(x>=y) ans|=x<<i; else ans|=y<<i,m-=1<<i; } else ans|=calc(0,i)<<i; } printf("%d\n",ans); return 0; }