题目
题目大意
有n扇门,每个门都有一个操作a和一个数b。
a一共有三种类型,分别是“OR、XOR、AND”。
”OR“是让你进这扇门之前的值和这扇门的值b执行”按位或“操作。
“XOR”是与这扇门的值b,执行“按位异或”的操作。
“AND”是执行“按位与”的操作。
然后你有一个初始值x,x为0到m的一个整数值,要求你选择一个x的值,使经过这n扇门之后,使x的值最大。
思路
因为每一次操作都是按位操作,所以每一位取什么值对其它位没有影响。
例如,初始值位5,5的二进制为101,我们有2扇门,分别为{“OR”,3},{“AND”,4}。
3的二进制使011,4的二进制是100,那么走过这2扇门进行的操作分别是,(1|0)&1、(0|1)&0、(1|1)&0、结果为100,10进制表示为4。
所以我们可以考虑从高位到低位,依次考虑每一位填0还是填1。
如果第k位填1,应该满足以下条件。
1.已经填好的数得值加上1<<k不超过m。
2.如果k位填1后进行的运算(用1和1到n扇门的第k位进行运算)得到得答案是1,并且填0得到的答案是0.
如果不满足上述条件,要么填0比填1更优,要么填1会超过m的范围。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e5+7;
ll a[N];
pair<string,ll>p[N];
ll n,m;
ll AC(int now,ll x)
{
for(int i=0;i<n;i++)
{
if(p[i].first=="AND") x&=p[i].second>>now&1;
else if(p[i].first=="OR") x|=p[i].second>>now&1;
else x^=p[i].second>>now&1;
}
return x;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=0;i<n;i++)
{
string s;ll b;
cin>>s>>b;
p[i].first=s;
p[i].second=b;
}
ll ans=0,val=0;
for(int i=29;i>=0;i--)
{
ll ans1=AC(i,0);
ll ans2=AC(i,1);
if((val+(1<<i))<=m&&ans1<ans2)
{
val+=1<<i;
ans+=ans2<<i;
}
else
ans+=ans1<<i;
}
cout<<ans<<endl;
return 0;
}