1、二进制位运算解法:计算0的个数,判断与或条件
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5;
int a[N],cnt[N];
int main(){
int n,p;
while(~scanf("%d%d",&n,&p)){
memset(a,0,sizeof(a));
memset(cnt,0,sizeof(cnt));
int ans3=0;
int max=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
ans3^=a[i]; //异或
int tmp=a[i];
int len=0;
while(tmp){
if(tmp%2) cnt[len]++;
tmp>>=1; //左移
len++;
if(max<len)
max=len;
}
}
for(int i=0;i<max;i++) //0的个数
cnt[i]=n-cnt[i];
int op;
for(int i=0;i<p;i++){
scanf("%d",&op);
int t=a[op-1];
int ans1=0,ans2=0;
for(int j=0;j<max;j++){
if(cnt[j]==0||(cnt[j]==1&&t%2==0)) //0个数为0的话,则与,或都要运算; 如果0个数为1,而不要的数本位是0,则剩余0个数也为0
ans1+=1<<j,
ans2+=1<<j;
// else if((cnt[j]==n-1&&t%2==0&&n!=2)|| //如果0个数为n-1,而不要的数本位为0,则剩余0个数为n-2
// (cnt[j]==1&&t%2!=0&&n!=2)|| //如果0个数为1,而不要的数本位不为0,则剩余0个数为1
// (cnt[j]>1&&cnt[j]<n-1)) //剩余情况
else if(n-cnt[j]>1||(n-cnt[j]==1&&t%2==0)) //与上面注释的else if意思相同,这个更好理解
ans2+=1<<j;
t>>=1;
}
printf("%d %d %d\n",ans1,ans2,ans3^a[op-1]);
}
}
return 0;
}
2、前缀后缀思路:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5;
struct NODE{
int anda,ora,xora;
}s[N],ss[N];
int a[N];
int main(){
int n,q;
while(~scanf("%d%d",&n,&q)){
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
s[1].anda=a[1];
s[1].ora=a[1];
s[1].xora=a[1];
ss[n].anda=a[n];
ss[n].ora=a[n];
ss[n].xora=a[n];
for(int i=1;i<=n;i++){
if(i>1){ //前缀
s[i].anda=a[i] & s[i-1].anda;
s[i].ora=a[i] | s[i-1].ora;
s[i].xora=a[i] ^ s[i-1].xora;
}
if(i<n){ //后缀
ss[n-i].anda=a[n-i] & ss[n-i+1].anda;
ss[n-i].ora=a[n-i] | ss[n-i+1].ora;
ss[n-i].xora=a[n-i] ^ ss[n-i+1].xora;
}
}
while(q--){
int op;scanf("%d",&op);
if(op>1&&op<n)
printf("%d %d %d\n",s[op-1].anda&ss[op+1].anda,s[op-1].ora|ss[op+1].ora,s[op-1].xora^ss[op+1].xora);
else if(op==1)
printf("%d %d %d\n",ss[op+1].anda,ss[op+1].ora,ss[op+1].xora);
else if(op==n)
printf("%d %d %d\n",s[op-1].anda,s[op-1].ora,s[op-1].xora);
}
}
return 0;
}