【积累】关于与或异或的一个积累

关于与或异或的积累

1,例题1

题意:

\(n\) 个操作: op a ,有 \(3\) 种:

  • \(op_i=1\) ,表示将 \(x\)\(a_i\) 做与运算;
  • \(op_i=2\) ,表示将 \(x\)\(a_i\) 做或运算;
  • \(op_i=3\) ,表示将 \(x\)\(a_i\) 做异或运算。

要求将 \(n\) 个操作缩小成 小于等于 \(5\)个操作,使得对于任意 \(x\) ,进行这 \(n\) 个操作后的结果与 进行这 \(m\) 个操作的结果一致。

其中 \(0\leq a_i\leq2^{20}-1\)

解:

先分别算出 \(x_i=0\)\(x_i=1\) 在这 \(n\) 个运算之后的结果。

\(x\) 设置 \(3\) 种运算,例如 ((x&a)^b)|c 或者 ((x&a)|b)^c 等等;

将二进制位的每一位独立开来看,然后对于 \(x_i=0\)\(x_i=1\) 进行 \(n\) 种运算之后的结果,设置对应的运算数值。

例如 设置的运算时 ((x&a)^b)|c ,那么,

\(x_i=0\)\(x_i=1\) 进行 \(n\) 种运算之后的结果分别是 \(0\)\(0\) ,可以设 \(a_i=0\)\(b_i=0\)\(c_i=0\) ;

\(x_i=0\)\(x_i=1\) 进行 \(n\) 种运算之后的结果分别是 \(0\)\(1\) ,可以设 \(a_i=1\)\(b_i=0\)\(c_i=0\) ;

\(x_i=0\)\(x_i=1\) 进行 \(n\) 种运算之后的结果分别是 \(1\)\(0\) ,可以设 \(a_i=1\)\(b_i=1\)\(c_i=0\) ;

\(x_i=0\)\(x_i=1\) 进行 \(n\) 种运算之后的结果分别是 \(1\)\(1\) ,可以设 \(c_i=1\) ;

其余同理。

代码:

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define mkp(a,b) make_pair(a,b)
using namespace std;
typedef long long ll;
const int maxn=1e6+5;

int a[22],b[22];
int main()
{
	for(int i=0;i<20;i++)a[i]=1;
	int n,op,x,t,c;
	scanf("%d",&n);
	while(n--)
	{
		scanf("%d%d",&op,&x);
		for(int i=0,c=0;i<20;i++,x>>=1,c++)
		{
			t=x&1;
			if(op==1)a[c]&=t,b[c]&=t;
			else if(op==2){
				a[c]|=t;b[c]|=t;
			}else{
				a[c]^=t;b[c]^=t;
			}
		}
	}
	x=0;int y=0,z=0;
	for(int i=0,t=1;i<20;i++,t<<=1)
	{
		if(a[i]==0&&b[i]==0);
		else if(a[i]==1&&b[i]==0)x|=t;
		else if(a[i]==0&&b[i]==1)x|=t,y|=t;
		else if(a[i]==1&&b[i]==1)z|=t;
	}
	printf("3\n1 %d\n3 %d\n2 %d\n",x,y,z);
}

2,例题2

题意:

给定 \(n\)\(m\)\(2\le n \le10^5,0\le m\le 10^9\) , $ x \le m$

\(n\) 个操作 :op a , 有 \(3\) 种:

  • \(op_i=AND\) ,表示将 \(x\)\(a_i\) 做与运算;
  • \(op_i=OR\) ,表示将 \(x\)\(a_i\) 做或运算;
  • \(op_i=XOR\) ,表示将 \(x\)\(a_i\) 做异或运算。

询问最后可得到的最大值是多少。

解:

先分别算出 \(x_i=0\)\(x_i=1\) 在这 \(n\) 个运算之后的结果。

答案要求最大,那么就是尽可能先让最终值的最高位为1:

\(x_i=0\),而终值是 \(1\) 时 ,可以直接让答案 + \(1<<i\),因为 \(x_i=0\) ,不会影响 \(x\)\(m\) 的关系;

否则,如果 \(x_i=1\) ,而终值也是 1,且对于当前 \(m\)\(m\ge (1<<i)\) ,则让答案+ \(1<<i\) ,且让 \(m-=1<<i\) 。(贪心)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;

char s[5];
int main()
{
	int n,m,x=0x7fffffff,y=0,v;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%s%d",s,&v);
		if(s[0]=='A')x&=v,y&=v;
		else if(s[0]=='O')x|=v,y|=v;
		else x^=v,y^=v;
	}
	int res=0;
	for(int i=30;i>=0;i--){
		if(y&(1<<i))res+=1<<i;
		else if(x&(1<<i)&&m>=(1<<i))m-=1<<i,res+=1<<i;
	}
	printf("%d\n",res);
}
posted @ 2020-11-15 15:24  草丛怪  阅读(229)  评论(0编辑  收藏  举报