起床困难综合征

题目

起床困难综合症

题目大意

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

猜你喜欢

转载自blog.csdn.net/qq_44828887/article/details/103315200