题目大意:给一些操作(只能是AND,OR,XOR),在极大值范围内选择一个数,使得这个数经过操作之后得到的值最大。
思路:很水,只要不O(n)的枚举,基本怎样都能过。
我的写法是先预处理题目给的操作,看每一位经过操作之后得到的数值,然后从最高位到最低位贪心的取值,在不超过极大值的情况下,尽量让当前位运算之后为1
一定要注意是从最高位到最低位,因为最高位取1一定比剩下位全取1还要优,这个题就水A了
CODE:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
struct Complex{
int opt;
bool num[31];
int p;
Complex() {
p = 0;
memset(num,false,sizeof(num));
}
}ask[100100];<span style="white-space:pre"> </span>//注意范围,这里还WA了一次。。
int cnt,_max;
int temp[40];
char s[10];
bool ans[30];
inline bool Check(bool flag,int pos);
int main()
{
cin >> cnt >> _max;
for(int x,i = 1;i <= cnt; ++i) {
scanf("%s%d",s,&x);
if(s[0] == 'O') ask[i].opt = 1;
if(s[0] == 'X') ask[i].opt = 2;
if(s[0] == 'A') ask[i].opt = 3;
while(x) {
if(x&1) ask[i].num[ask[i].p] = true;
x >>= 1;
ask[i].p++;
}
}
temp[0] = 1;
for(int i = 1;i <= 30; ++i)
temp[i] = temp[i - 1] << 1;
int now = 0,k = 1,re = 0;
for(int i = 30;i >= 0; --i) {
if(Check(false,i))
re += temp[i];
else if(Check(true,i))
if(now + temp[i] <= _max) {
now += temp[i];
re += temp[i];
}
}
cout << re;
return 0;
}
inline bool Check(bool flag,int pos)
{
for(int i = 1;i <= cnt; ++i) {
switch(ask[i].opt) {
case 1:flag = flag | ask[i].num[pos]; break;
case 2:flag = flag ^ ask[i].num[pos]; break;
case 3:flag = flag & ask[i].num[pos]; break;
}
}
return flag;
}