起牀困難綜合徵

題目

起牀困難綜合症

題目大意

有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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章