ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

起床综合困难症(位运算)

2021-07-26 23:57:35  阅读:179  来源: 互联网

标签:运算 攻击力 int atm 困难 起床 防御 drd


我也得了起床综合困难症…啊啊啊
好了,停,还是直接开始吧
先放题目链接:

https://www.luogu.com.cn/problem/P2114

题目描述

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受到多少伤害。
输入输出样例
输入样例#1:
3 10
AND 5
OR 6
XOR 7
输出样例#1:
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~m,大家都挺喜欢超时的哈哈哈

思考:位运算的特征

我们知道,在计算机里数字按二进制存储,也就是一个数的每一位不是0就是1,当0、1进行相同次序的位运算以后得出来的也是0、1。

m<=10^9,即m的位数不超过30位。

我们需要最后进行位运算以后的答案最大,也就是说,从最高位开始到最低位,我们要让每一位尽可能为1。

例如,我们有3位,从第三位开始,我们让第三位为1,即100,值为4,如果第三位为0,值为0;
第二位为1,得到110,值为6,010值为2,000值为0;

总结一下就是,当一个数的第i位经过一系列位运算为1时,对答案的贡献就是1<<i;
当一个数的第i位经过一系列位运算为0时,对答案没有贡献。

那么,我们考虑当一个数的第i位经过一系列位运算为1时的情况:
情况1.第i位数原来是0,经过一系列位运算变成1;
情况2.第i位数原来是1,经过一系列位运算变成1;

对于情况1:如果第i位原来是0,后来变成了1,0~m的二进制中,可以任意实现第i位是0,所以答案直接计算加上贡献值1<<i;
对于情况2:第i位数原来是1,经过一系列位运算变成1,然而,对于这种情况,必须是i小于m是1的最高位,因为大于m是1的最高位就超出了m的范围;
例如5,转换为二进制是101,那么i<=3;
转换一下,也就是说,这个条件是:(1>>i)的值小于m;
这里要注意,计算完以后要让m的这一位变成0,即101,变成001,不然当i=2时,也小于m=5,判断错误。

那么我们只需要对30位全是0,和30位全是1,即a0=0,二进制为000000…,a1=-1,二进制为11111…,来进行一系列的位运算。
然后根据位运算后是1的情况来进行对最后答案的计算。

代码如下:

#include<bits/stdc++.h>
using namespace std;

int a1=0,a2=-1;
int ans=0;

int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;++i)
	{
		char str[5];
		scanf("%s",str);
		int x; cin>>x;
		if(str[0]=='A')			a1&=x,a2&=x;
		else if(str[0]=='O')	a1|=x,a2|=x;
		else if(str[0]=='X')	a1^=x,a2^=x;
	}
	for(int j=29;j>=0;--j)
	{
		if((a1>>j)&1)	ans+=(1<<j);//第i位原来是0
		else if((a2>>j)&1&&(1<<j)<m)	ans+=(1<<j),m-=(1<<j);//第i位原来是1
	}
	printf("%d\n",ans);
	return 0;
} 

这次的位运算学习,就到今天结束了。
这一次复盘位运算又学到了很多东西,位运算真的是十分巧妙有趣的东西,还需要通过反复实践琢磨。
明天开始第二部分的递推与递归,希望打败了巨龙的我不再起床困难了。

最后,放一个小总结:
1.位运算的关键是二进制0、1的问题
2.0、1可以用来表示多种情况,选与不选
3.利用二进制+位运算可以有效地降低时间复杂度。

下次位运算,再会啦。

标签:运算,攻击力,int,atm,困难,起床,防御,drd
来源: https://blog.csdn.net/jigsaw_zyx/article/details/119120658

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有