BZOJ3668/UOJ2 [NOI2014]起床困难综合症
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
Description
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 受到多少伤害。
Input
第1行包含2个整数,依次为n,m,表示drd有n扇防御门,atm的初始攻击力为0到m之间的整数。接下来n行,依次表示每一扇防御门。每行包括一个字符串op和一个非负整数t,两者由一个空格隔开,且op在前,t在后,op表示该防御门所对应的操作, t表示对应的参数。n<=10^5
Output
一行一个整数,表示atm的一次攻击最多使 drd 受到多少伤害。
Sample Input
AND 5
OR 6
XOR 7
Sample Output
HINT
正解:贪心+位运算
解题报告:
这道题作为NOI2014的day1T1还是送的挺良心的...
考虑m的每一位只有两种状态可取,而且位与位之间互相独立,所以分开考虑即可。
每一位若是能取0而使得最终这一位是1,显然这是最优情况,并且一定合法;
若这一位取1而使得最终答案中这一位是1,当且仅当这一位取1之后不超过m时合法;
否则无论如何都不能使得最终答案这一位为1,取0即可。
//It is made by ljh2000 #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <queue> using namespace std; typedef long long LL; const int MAXN = 100011; int n,m,type[MAXN],val[MAXN],ans,now; char ch[12]; inline int getint(){ int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w; } inline int getans(int wei,int ini){ for(int i=1;i<=n;i++) { if(type[i]==1) ini&=(val[i]>>wei); else if(type[i]==2) ini^=(val[i]>>wei); else ini|=(val[i]>>wei); } return ini&1; } inline void work(){ n=getint(); m=getint(); for(int i=1;i<=n;i++) { scanf("%s",ch); if(ch[0]=='A') type[i]=1;//AND else if(ch[0]=='X') type[i]=2;//XOR else type[i]=3;//OR val[i]=getint(); } for(int i=30;i>=0;i--) { if(getans(i,0)) { ans|=(1<<i); continue; } if(now+(1<<i)<=m && getans(i,1)) { now|=(1<<i); ans|=(1<<i); continue; } } printf("%d",ans); } int main() { work(); return 0; }