目录
1.题目
题目描述
有一组整数 {0,1,2,…,2m -1}, 请从中选出 k 个数,使得这k个数的异或和为n, 请输出最大的满足条件的 k。
输入
第一行一个数t,代表多组样例输入
每组两个数n和m, 其中 0≤n≤2m-1,1≤m≤60
输出
输出每组最大的满足条件的k。
样例输入
1 2 2
样例输出
3
2.解题思路
因为题目要求的从0到里找到最多的k个数,异或后值等于n,因为这k个数进行的是异或运算,也就是这k个数的二进制的每一位上进行的都是异或运算,因为异或运算,同为1异或后为零,仅有1个1异或后为0,也就是说,偶数个1异或后为0,奇数个1异或后为1,经证明知当m不为1时,从0到的每个数的二进制的各个位上的1相加都为偶数(证明详见附录)。
因为从0到m-1位的1的总数都为偶数,所以当m!=1时,将这些数都异或后都为0,而题目要求k个数异或后为n,那我们可以根据n的二进制表示的每一位0或者1,由全部数进行异或后为0进行调整,若对应位为0则不变,若为1则可以使对应位1的总数-1。
经过调整后发现,要调整的01序列,其实就是最后异或得出的n的二进制表示,所以将除去n之外的所有数进行异或就得到了n,则其异或的个数的最大值k=个.比较特殊的情况是,当n=0时,因为0的二进制表示的每一位都为0,因此将0减去后异或的数与不减去0异或后的数相等,而题目要求的k是最多的异或个数,故当n=0时,k=个,当m=1时,则需要另外进行特判。
3.代码思路
所以,当m!=1且n!=0时,输出,当m==1且n==1时,输出2,当m==1且n==0时,输出1,其余情况
4.代码实现
#include<iostream>
using namespace std;
long long cj(long long m)
{
long long ans=1;
for(int i=1;i<=m;i++) ans=ans<<1;
return ans;
}
int main()
{
int t;
cin >>t;
while(t--)
{
long long n,m;
cin >>n >>m;
if(n!=0&&m!=1) cout <<(cj(m)-1) <<endl;
else if(n==1&&m==1) cout <<2 <<endl;
else if(n==0&&m==1) cout <<1 <<endl;
else cout <<cj(m) <<endl;
}
return 0;
}
5.附录
推导: 当m不为1时,从0到的每个数的二进制的各个位上的1相加都为偶数
简单列举从0到
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
观察发现低位即第1位 ,01交替变化为每隔交替1次,交替完1次算一个周期,周期为,即个
第二位,01交替变化为每隔交替1次,周期为个
第三位,01交替变化为每隔交替1次,周期为个
第四位,01交替变化为每隔交替1次,周期为个
.......
以此类推,第t位的周期个数为个,而1与0在每个周期中是成对存在的,则每一位的1的个数为周期个数除2,结果为偶数。
推导结束