题目大意
给定两个数 l , r l, r l,r,将 [ l , l + 1 , . . . , r − 1 , r ] [l, l + 1,..., r-1, r] [l,l+1,...,r−1,r]的一个任意排列,全部异或 x x x,得到一个新的数组 a a a。
给定 l , r l, r l,r和 a a a数组,求 x x x。
其中 0 = l ≤ r ≤ 2 17 0 = l \le r \le 2^{17} 0=l≤r≤217
思路
我们按位处理,我们计算异或前的数组每一位 1 1 1的个数,设为 c n t A cntA cntA,计算异或后的数组每一位 1 1 1的个数,记为 c n t B cntB cntB
-
那么一旦 c n t A i ! = c n t B i cntA_i != cntB_i cntAi!=cntBi,那么就说明 x x x这一位一定为 1 1 1
-
对于 c n t A i = = c n t B i cntA_i == cntB_i cntAi==cntBi一样的位数,说明这一位可以为 1 1 1,也可以为 0 0 0。
因为 l = 0 l=0 l=0,所以2.总是成立,因为异或后的数组一定有一个 x x x,异或前有个 0 0 0,所以 x x x某一位为 1 1 1,那么异或后的数这一位 1 1 1的数量一定会变化。
而一旦 l ≠ 0 l \not = 0 l=0,那么就有可能 1 1 1变为 0 0 0, 0 0 0变为 1 1 1的数量相同,抵消掉了,比如 [ 1 , 2 ] ⊕ 2 = [ 0 , 3 ] [1,2] \oplus 2 = [0,3] [1,2]⊕2=[0,3],前后每一位 1 1 1的数量都相同。
代码
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int maxN = 1e5 + 7;
int T, l, r, cnt1[53], cnt2[53];
inline void calc(int *cnt, int x)
{
int now = 0;
while(x) {
if(x & 1)
cnt[now]++;
now++; x >>= 1;
}
}
int main()
{
scanf("%d", &T);
while(T--) {
memset(cnt1, 0, sizeof cnt1);
memset(cnt2, 0, sizeof cnt2);
scanf("%d%d", &l, &r);
for(int i = l; i <= r; ++i) {
calc(cnt1, i);
int x; scanf("%d", &x);
calc(cnt2, x);
}
int ans = 0;
for(int i = 0; i < 31; ++i)
if(cnt1[i] != cnt2[i])
ans |= (1 << i);
printf("%d\n", ans);
}
return 0;
}