关于与或异或的积累
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) 个操作的结果一致。
其中 (0leq a_ileq2^{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
1 %d
3 %d
2 %d
",x,y,z);
}
2,例题2
题意:
给定 (n) 和 (m) ,(2le n le10^5,0le mle 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) , (mge (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
",res);
}