题目:
http://acm.hdu.edu.cn/showproblem.php?pid=6186
题意:
给出一个长度为n的数组a,对于每次询问,给出一个数字p,意为去掉数字a[p],然后求数组中其余n-1个数字的按位与,按位或,按位异或。
思路:
首先把每个数字化成二进制记录每个位置上0、1的个数,对于询问,计算出a[p]二进制中每个位置上0、1的个数。对于按位与,从二进制角度看,只要当前位置上有一个0,那么当前位置的值就是0,对于按位或,只要当前位置上有一个1,那么当前位置的值就是1。而按位异或,首先求出所有数字的按位异或,再与a[p]异或一下,就可以了
#include <bits/stdc++.h>
using namespace std;
const int N = 100000 + 10, INF = 0x3f3f3f3f;
int a[N];
int num1[35], num0[35], tmp1[35], tmp0[35];
int len = 31;
void work(int x, int num1[], int num0[])
{
for(int i = len-1; i >= 0; i--)
{
int j = 1 & (x >> i);
if(j) num1[i]++;
else num0[i]++;
}
}
int main()
{
int n, m;
while(~ scanf("%d%d", &n, &m))
{
memset(num0, 0, sizeof num0);
memset(num1, 0, sizeof num1);
int _xor = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
work(a[i], num1, num0);
_xor ^= a[i];
}
int p;
for(int i = 1; i <= m; i++)
{
scanf("%d", &p);
memset(tmp0, 0, sizeof tmp0);
memset(tmp1, 0, sizeof tmp1);
work(a[p], tmp1, tmp0);
int ans1 = 0;
for(int j = len-1; j >= 0; j--)
if(num0[j] - tmp0[j] == 0 && num1[j] - tmp1[j] != 0) ans1 = ans1 * 2 + 1;
else ans1 = ans1 * 2 + 0;
int ans2 = 0;
for(int j = len-1; j >= 0; j--)
if(num1[j] - tmp1[j] != 0) ans2 = ans2 * 2 + 1;
else ans2 = ans2 * 2 + 0;
int ans3 = _xor ^ a[p];
printf("%d %d %d\n", ans1, ans2, ans3);
}
}
return 0;
}