起床困难综合症

主要知识点

二进制状态压缩
位运算

二进制状态压缩

是指将一个长度为m的bool数组对应到一个m位二进制整数,即用二进制整数来表示状态。

位运算

操作运算
取出整数n在二进制表示下的第k位(n >> k)& 1
取出整数n在二进制表示下的第0 ~ k-1位(1 << k) - 1 & n
把整数n在二进制表示下的第k位取反n xor (1 << k)
对整数n在二进制表示下的第k位赋值1n or (1 << k)
对整数n在二进制表示下的第k位赋值0n & (~(1 << k))

lowbit 运算
lowbit(n) :非负整数n在二进制表示下 ,最低位的1及其后边所有的0构成的数。
补码表示下, ~n = -1 - n
lowbit(n) = n & ( ~n + 1) = n & (-n)
lowbit运算可以找出整数二进制表示下所有是1的位
lowbit属于树状数组内的基本运算

题目

21世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳。
作为一名青春阳光好少年,atm 一直坚持与起床困难综合症作斗争。
通过研究相关文献,他找到了该病的发病原因: 在深邃的太平洋海底中,出现了一条名为 drd 的巨龙,它掌握着睡眠之精髓,能随意延长大家的睡眠时间。
正是由于 drd 的活动,起床困难综合症愈演愈烈, 以惊人的速度在世界上传播。为了彻底消灭这种病,atm 决定前往海底,消灭这条恶龙。
历经千辛万苦,atm 终于来到了 drd 所在的地方,准备与其展开艰苦卓绝的战斗。drd 有着十分特殊的技能,他的防御战线能够使用一定的运算来改变他受到的伤害。
具体说来,drd 的防御战线由 n扇防御门组成。每扇防御门包括一个运算 op和一个参数 t,其中运算一定是 OR,XOR,AND中的一种,参数则一定为非负整数。如果还未通过防御门时攻击力为 x,则其通过这扇防御门后攻击力将变为 x op t。
最终 drd 受到的伤害为对方初始攻击力 x依次经过所有 n扇防御门后转变得到的攻击力。
由于 atm 水平有限,他的初始攻击力只能为 0到 m 之间的一个整数(即他的初始攻击力只能在 0,1,…,m 中任选,但在通过防御门之后的攻击力不受 m的限制)。
为了节省体力,他希望通过选择合适的初始攻击力使得他的攻击能让 drd 受到最大的伤害,请你帮他计算一下,他的一次攻击最多能使 drd 受到多少伤害。
输入格式
第 1行包含 2 个整数,依次为 n,m,表示 drd 有 n 扇防御门,atm 的初始攻击力为 0 到 m之间的整数。
接下来 n行,依次表示每一扇防御门。每行包括一个字符串 op 和一个非负整数 t,两者由一个空格隔开,且 op 在前,t 在后,op 表示该防御门所对应的操作,t表示对应的参数。
输出格式
输出一个整数,表示 atm 的一次攻击最多使 drd 受到多少伤害。
数据范围
输入样例:
3 10
AND 5
OR 6
XOR 7
输出样例:
1
样例解释
atm可以选择的初始攻击力为 0,1,…,10。
假设初始攻击力为 4,最终攻击力经过了如下计算
4 AND 5 = 4
4 OR 6 = 6
6 XOR 7 = 1
类似的,我们可以计算出初始攻击力为 1,3,5,7,9时最终攻击力为 0,初始攻击力为 0,2,4,6,8,10 时最终攻击力为 1,因此 atm 的一次攻击最多使 drd 受到的伤害值为 1。
运算解释
在本题中,选手需要先将数字变换为二进制后再进行计算。如果操作的两个数二进制长度不同,则在前补 0至相同长度。

#include <iostream>
#include <string>
using namespace std;

const int N = 1e5 + 7;
typedef struct door{
	char op[6];
	int t;
}door, d[N];

d a;
int n , m;
int ans=0 ;


int calcu(int bit, int b)
{   //依次过一遍所有的门
	for(int i = 0; i < n; i ++)
	{
		int x = 1 & ((a[i].t) >> bit);
		string action = (string)a[i].op;
		if(action == "AND")
		{
			b &= x; 
		}else if(action == "OR")
		{
			b |= x;
		}else
			b ^= x;
		
	}
	
	return b;
}
int main()
{
  
  cin >> n >> m;
  for(int i=0; i < n; i++)
    scanf("\n%s %d",a[i].op,&a[i].t);
    
  //algorithm
  int c = 0;
  for(int bit = 29;bit >= 0;bit --)
  {
  	int x =calcu(bit,0);
  	int y =calcu(bit,1);
  	if(x < y && c + (1 << bit) <= m)//表明y是1,原数对应位set 1
  	{
  		ans |= y << bit;
  		c |= 1 << bit;
	  //ans += y << bit; 
  		
	}else
		ans |= x << bit;
  }
  cout << ans << '\n';
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值