題目
題目大意
有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;
}