Luogu P2114 起床困难综合征

Luogu P2114 起床困难综合征

本题的关键之处在于,题目中给定的三种位运算——AND,OR,XOR,在二进制下皆是不进位的。这说明每一位都是独立的,启发我们可以按位考虑。
因此我们从最高位向最低为依次考虑,每一位应该填$0$还是$1$。
因为题目中 $m \leq 10^9$ ,所以最多有 $30$ 位。( $10^9 < 2^{30}-1$ )
对于第$k$位(最低位为第$0$位),改为应该填$1$,当且仅当满足下列两个条件:

  1. 已经填好的更高位构成的数值加上$2^k\ (1<<k)$之后不超过$m$;
  2. 用每个参数的第$k$位参与全部位运算。在所有位运算结束后保持不变。

易知,对于条件2,如果不满足,则说明填$1$不如填$0$更优。
在依次考虑完每一位后,就得到了答案。

#include<bits/stdc++.h>
#define N 100010

using namespace std;

int n,m,t,cnt,ans,tmp;
char c[5];

struct node {
	int op,t;
}a[N];

void Read() {
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) {
		scanf("%s%d",c,&t);
		if(c[0]=='A') {
			a[++cnt].op=1;
		}
		else if(c[0]=='O') {
			a[++cnt].op=2;
		}
		else if(c[0]=='X') {
			a[++cnt].op=3;
		}
		a[cnt].t=t;
	}
	return;
}

int Calc(int bit,int val) {
	int ret=val;
	for(int i=1;i<=n;i++) {
		int x=(a[i].t>>bit)&1;
		if(a[i].op==1) {
			ret&=x;
		}
		else if(a[i].op==2) {
			ret|=x;
		}
		else if(a[i].op==3) {
			ret^=x;
		}
	}
	return ret;
}

void Solve() {
	for(int i=29;i>=0;i--) {
		int val0,val1;
		val0=Calc(i,0);
		val1=Calc(i,1);
		if(tmp+(1<<i)<=m&&val0<val1) {
			tmp+=(1<<i);
			ans+=(val1<<i);
		}
		else {
			ans+=(val0<<i);
		}
	}
	printf("%d",ans);
	return;
}

int main()
{
	Read();
	Solve();
	return 0;
}
posted @ 2019-11-21 22:47  WalkerV  阅读(141)  评论(0编辑  收藏  举报