哈理工OJ-2331-Great Atm
题意:
有m+1个数,分别是0~m,从中选取一个数进行n轮(&,|,^)操作后使得最后的结果最大,并输出这个结果
补一个二进制运算【学习一下】
1.按位与运算符(&)
参加运算的两个对象,按二进制位进行“与”运算
运算规则:
0 & 0 = 0;0 & 1 = 0;1 & 0 = 0;1 & 1 = 1;
例如:
3 & 5
0011 & 0101 = 0001
因此 3 & 5 = 1
2.按位或运算符(|)
参加运算的两个对象,按二进制位进行“或”运算
运算规则:
0 | 0 = 0;0 | 1 = 1;1 | 0 = 1;1 | 1 = 1;
例如:
3 | 5
0011 & 0101 = 0111
因此 3 | 5 = 7
3.按位异或运算符(^)
参加运算的两个对象,按二进制位进行“异或”运算
运算规则:
0 ^ 0 = 0;0 ^ 1 = 1;1 ^ 0 = 1;1 ^ 1 = 0;
例如:
3 ^ 5
0011 ^ 0101 = 0110
因此 3 ^ 5 = 6
4.取反运算符(~)
参加运算的两个对象,按二进制位进行“取反”运算
运算规则:
~1 = 0; ~0 = 1;
即:对一个二进制数按位取反,即将0变1,1变0
例如:
~9
即1001 变成 0110
5.左移运算符(<<)
将一个运算符对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。
例如:a = a << 2 将 a 的二进制位左移2位,右边补0,
左移1位后a = a * 2;
若左移时舍弃的高位不包含1,则每左移以为,相当于 该数乘以2
6.右移运算符(>>)
将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃.
操作数每右移一位,相当于该数除以2.
例如:a = a >> 2 将a的二进制位右移2位,
左补0 或 补1 即被移数是正还是负。
二进制32位 第32位是运算符号,总共31位数字
思路:
可以先求出二进制的每一位都为0进行n轮操作所得的结果和二进制的每一位都为1进行n轮操作所得的结果,并且分别记录下出所得结果的二进制上每一位的数。
最后遍历二进制的31位,如果原先这一位为0,但操作后的结果中这一位为1,那么最后的答案肯定要加上这一位(≤m的数中这一位肯定可以为0);
如果原先这一位为1,操作后的结果中这一位也为1,此时我们要先判断这一位的十进制是否大于m,如果不大于那么最后答案也要加上这一位(因为≤m的数中这一位可以为1),最后加得的答案就是最终的结果了
加重的重点!!
看了半天才懂题意,没有思路
感谢:http://blog.csdn.net/blesslzh0108/article/details/68957626
#include<stdio.h>
int temp[40][2];
int main()
{
int n,m,x;
char s[10];
while(~scanf("%d%d",&n,&m))
{
int Max=2147483647,Min=0;//
for(int i=0; i<n; ++i)
{
scanf("%s %d",s,&x);
if(s[0]=='A')
Max&=x,Min&=x;
else if(s[0]=='O')
Max|=x,Min|=x;
else if(s[0]=='X')
Max^=x,Min^=x;
}
for(int i=30; i>=0; --i)//记录二进制的每一位为0或为1时所得的(二进制中这一位的)结果
{
temp[i][0]=(Min&(1<<i));
temp[i][1]=(Max&(1<<i));
}
int ans=0;
for(int i=30; ~i; --i)
{
if(temp[i][0])
ans=ans|(1<<i);
else if(temp[i][1])
{
if((1<<i)<=m)
{
ans=ans|(1<<i);
m-=(1<<i);
}
}
}
printf("%d\n",ans);
}
return 0;
}